本帖最后由 shane007 于 2023-9-5 16:49 编辑
; B2 {8 T* b$ i% H T) C" _- c/ c' r2 L# d. \- N
这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎9 P1 S0 a% w. K- ~3 r+ X
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
3 ]1 M8 I7 Z& @! n4 {https://www.chinaavg.com/forum.php?mod=viewthread&tid=1540811 A& ]* ]1 e2 L9 i4 y- l$ `
第1处! ?' B& \0 b+ r$ q' Y/ x
- void sub_451474(char *a1, ...)0 {9 ?* U& z6 E. F: }/ y7 N
- {
( |. i4 L+ d4 C4 ]8 N - GLsizei v1; // eax
0 A; n" f1 Q" P( n' f. ? - char lists; // [esp+4h] [ebp-800h]
1 C: I, ~7 v/ u0 h) i - va_list va; // [esp+810h] [ebp+Ch]
4 N" }/ a/ O- X- }5 { }
! O- I% [6 Z/ i1 F- va_start(va, a1);
; u# U: b2 T/ ~1 Z$ N, [2 l - if ( a1 )% C) g% Q& x- O( c' v& l% e
- {/ h! b$ p) a3 k8 H4 K% A9 F* V
- vsprintf(&lists, a1, va);* m1 @, d$ |! @3 c
- glPushAttrib(0x20000u);9 [ i* b4 J- [
- glListBase(base);" _' A0 z4 Y9 I3 S
- v1 = strlen(&lists);
8 o- i2 J* I6 K9 M - glCallLists(v1, 0x1401u, &lists);5 G2 V; k- v2 J8 M/ x; O
- glPopAttrib();" v2 B/ O( D1 p9 I1 p: F, Q1 r( F
- }
( i# b h2 H' h3 m; o; _0 W& H - }
复制代码
! s# H( a% r9 J7 X1 @% P6 p7 E, G# k6 a& C; X- j2 j. w! N
3 S0 v# I' X W) b- \; H' h第2处3 V* s l* @" z, U& p+ m. j7 h
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
# J. w, k8 z. z/ u- H0 I, i. c/ ]9 O7 X - {2 g9 K4 Z! \& F% h* |
- int v4; // eax; \7 v6 {9 \0 x5 l5 k0 f2 z
- GLsizei v5; // eax
+ q' M4 J# N U+ @4 V0 L3 w - char lists; // [esp+4h] [ebp-800h]
( l4 M# D4 a- K, J6 J - va_list va; // [esp+81Ch] [ebp+18h]
- c+ n, D/ w. j. R n+ t4 L! v+ E - # A5 j; }" E5 L
- va_start(va, a4);
: g7 W& Z. I! I% W' z - if ( a4 )* t( D" D+ p" M/ D; G0 y, b7 x& p# t" B
- {
2 s2 H1 w, Y3 V' x; x. V- c7 R# A# D - sub_44F8A0(a3);
: s( n3 v: O" L4 \* W: C. A - v4 = sub_40BB44();4 q, X) ]4 b6 B) {( ]9 W* y- p
- glRasterPos2i(x, v4 - a2);
7 c$ S/ N1 N" |* | - vsprintf(&lists, a4, va);
7 c' V2 g/ i# \ - glPushAttrib(0x20000u);" S9 w6 i* o D9 ^' D" h: Z5 w
- glListBase(base);% U6 U2 i+ `/ T" v
- v5 = strlen(&lists);
5 A9 v0 A4 m6 F7 u* q9 d - glCallLists(v5, 0x1401u, &lists);
" z4 K$ d, b9 p$ N; t+ i - glPopAttrib();: B% Z8 W% G3 C$ t1 {
- }8 p: ]+ j. T; L. ~" G
- }
复制代码
3 b! e! ?: n8 D9 ^/ J6 P3 r7 t: I+ \1 {0 \) m' f
& ?5 B, ]/ Q0 [% \第3处
) V7 j) V$ c5 J; u4 H6 B1 P1 b
( g+ n! V* f- q" _- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)
0 z' o4 z2 S9 c - {
$ s0 B, ]/ b# |, C - GLvoid *v7; // ST08_4
3 U2 Y, n: J6 w/ [. q - GLsizei v8; // eax
4 M3 S b& ~( r. z# H - int v9; // [esp+0h] [ebp-1018h]
/ e/ T7 U! R0 |! [ - char v10; // [esp+8h] [ebp-1010h]
) v: S# B$ ]8 p- l4 e; g - GLvoid *lists; // [esp+100Ch] [ebp-Ch]
+ r0 D* g- y! _/ X3 e - char v12[5]; // [esp+1013h] [ebp-5h]7 A7 h8 y$ ]; S- H) \- Q1 u6 s" c
- va_list va; // [esp+103Ch] [ebp+24h]
r- u% a, [) E+ c3 o; M
* A5 ^2 L# s( S2 X0 U4 k% j Z' n- va_start(va, a7);0 m3 z8 _) C+ `7 n4 n* d! a) o% O
- v9 = 1;
: }) a1 j! L" `2 q) I1 ]) {/ X - if ( a7 )6 G& X1 ?* y' M6 a( z0 t# I" w
- {6 u% d' ]/ D) A5 H
- vsprintf(&v10, a7, va);9 v9 E% ?8 u2 y" T# o
- glPushAttrib(0x20000u);
j* {1 l6 Z2 | - glListBase(base);
- J/ W- s, D8 d' a/ y' ^ - lists = &v10;+ ^0 g1 f& k- W# }/ T
- do
" b. I* [( e# T( d* M, _ - {
- X% [/ _! R2 m5 @. y5 x - *(_DWORD *)&v12[1] = lists;6 ]8 x+ G$ J3 F. e5 q' w( ^ z
- while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )" M% }9 G$ i, f/ Z: }; Z
- ++*(_DWORD *)&v12[1];: U" F' d# ?: M8 ?' i1 k1 b
- v12[0] = **(_BYTE **)&v12[1];
& e/ u& K/ Z; ^4 m1 ^" O - **(_BYTE **)&v12[1] = 0;( g. O" M. P/ W' C8 d
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 ), `- G, o. P: e X$ g
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
1 a; i, l6 l2 S - y -= a5;$ V& Z) L7 u1 _; b) Y
- glRasterPos2i(*(_DWORD *)a4 + a1, y);
- L( V) m( O7 E( c& h - v7 = lists;
, ]* P" ]# d& D1 y& a - v8 = strlen((const char *)lists);4 V9 y5 g) i6 Z9 C* I R& G
- glCallLists(v8, 0x1401u, v7);/ E+ A( m7 ?: S: T& K1 ^2 ]& N: b: u; P
- if ( v9 < a3 )! W* P1 X2 I9 @1 n4 u
- a4 += 4;* p2 r0 \+ f. i/ N6 _) l7 Y
- ++v9;3 k" l \2 ?' a) U- F
- lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);3 X" }, j7 v- d [% Y5 {* C9 w* P8 L
- }
) C) Q3 z$ w: ^" i( J0 V - while ( v12[0] );
/ Y. ^. a0 [- C - glPopAttrib();1 _, Q$ h6 E$ w
- }
- |/ ]- d' f' i7 _% X7 Y - }
* D; H" Z& F! J; p2 k% L$ j
复制代码 D h8 }9 ^5 [8 e& F% @2 P
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810# i. {+ w# W8 j7 R, X3 R: K' p& M# D
% d0 x* s6 S! \2 }! K- .text:004512B1 52 push edx ; char ** B Z9 a5 S, I$ C+ @6 O( R, a' v4 A
- .text:004512B2 8B 45 30 mov eax, [ebp+base]
- E# z7 ?/ J$ k& B9 U: O - .text:004512B5 50 push eax ; base
! F# T3 j! {1 R; J% M - .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
+ O2 L. e8 _( p, Q) h" @ - .text:004512B9 51 push ecx ; int7 m9 J( S( K( |7 n8 r, v
- .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]+ E( ~# _7 J$ H' _7 }
- .text:004512BD 52 push edx ; int' M5 Q: w1 b4 K+ O7 j2 E+ x
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
2 F X. i* V$ l! a9 z - .text:004512C1 50 push eax ; int
2 u" ^9 E. M& T8 q8 u - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]) C: ^ P2 T! o
- .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]+ T) A; M6 B r% F) ~! B, d8 G
- .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]
1 @3 E! ~( ~4 b - .text:004512CB 51 push ecx ; y
/ J" s$ X( X; s" p8 J - .text:004512CC 8B 55 08 mov edx, [ebp+x]* j- ^9 `, y7 s
- .text:004512CF 52 push edx ; int
* I3 A; J7 n. @* x - .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
3 Z+ `% D; D5 j# ^, I+ x# }+ cchatGPT整理过之后,如下" E" h' o7 X; G" B
9 T2 t9 a$ {5 R/ K& o0 F0 @- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
' E4 _0 T) L, c, p h$ _ - {
: Y4 ` [- w+ W) r# r7 x - GLvoid *textData; // 存储字符数据的指针
: M$ J- E; y7 z9 k/ v* E7 O - GLsizei textLength; // 字符数据的长度
3 I3 r. {# e/ `! J9 M - int lineIndex; // 行索引
9 x" p4 U+ G5 W - char formattedText[5]; // 存储格式化后的字符数据& z9 t8 I# V# D; J" g: b4 p1 d
- GLvoid *currentLine; // 当前行的字符数据指针
" q6 f3 T8 h6 a C0 v) ]% D, r - char buffer[5]; // 字符数据缓冲区7 o( ]( S6 H1 W7 j) z* k
- va_list args; // 变长参数列表
0 ^ m$ H/ T: v - 2 C$ m/ n+ l* `& S+ b- r* v+ @
- va_start(args, text); // 初始化变长参数列表7 M; M2 N, q) Q* b
- lineIndex = 1; // 初始化行索引为1
7 W9 K9 u8 L0 o/ ~% W+ w1 c
' i" n& K- o5 z7 O% V. i/ }1 z- if (text) // 如果文本不为空
% j5 y8 z$ P6 n' S4 p - {
% ~% O3 u' t6 [ - vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中" Q- I+ g4 @7 d+ F8 c" T
- glPushAttrib(0x20000u); // 推送OpenGL属性状态
3 Q% [$ p' N1 U8 l - glListBase(displayListBase); // 设置显示列表的基础值
- r, W- p- _, }. k: _2 \/ ^! g$ v - currentLine = formattedText; // 将currentLine指向formattedText的内存位置
[1 p+ k. m( a; C
5 O6 m* _ Y+ V: _# ]- do- C8 k5 }9 @% }
- {# ~0 n) Q8 Q# K, E& H
- *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素2 E, H% v3 x: f1 p$ h+ U9 o6 l( D
: W1 ?) _( G2 s4 e- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束6 q7 `+ z9 H2 v2 b( n
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
1 ]0 a. ]% O- Y9 r! w - / {* c! u* m/ K# J2 `1 q
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素
@: y+ m% w! x" u/ }4 q. I - **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符, c5 ^' y' [: S3 ]0 T
- ( Z# W5 i4 l$ z: N
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
! a. Z4 `& W, `3 {% |' V - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
! H; P* K' B0 z& d
$ |1 _1 ?( I' `7 j$ \" |- yOffset -= lineHeight; // 更新y坐标
# o/ O4 I7 _' F- `( Q - glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置
5 n& e; v$ s/ W/ Y @/ b - textData = currentLine; // 将textData指向currentLine
3 H6 m, t* S- y - textLength = strlen((const char *)textData); // 计算字符数据的长度' Y( p. Z- `- {( S1 @
- glCallLists(textLength, 0x1401u, textData); // 调用显示列表
1 H& Z4 v! r4 g3 u
" o6 [$ E3 T( j- ?. `+ e p9 J- if (lineIndex < numLines)( C. e [% t. b4 a, `1 s( R* W i
- lineOffset += 4; // 更新lineOffset& M% [5 l5 @! f. v9 o! F
- ++lineIndex; // 递增行索引
$ G/ \4 e8 e& z* _ @; T - currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
9 z2 q3 @% ?# ^8 q - }
- e. [) o. a f - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环4 s e8 e( b8 Y- F1 _3 z1 P- B
- glPopAttrib(); // 恢复OpenGL属性状态, L2 e2 f! ^1 q5 X7 Z
- }5 \# r- P1 Q! T7 T( R6 _
- } X$ I5 n, X' i7 e; ]
复制代码 3 U5 Q3 B b* T( x
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
8 t; D: p0 c+ F+ k! f
/ j1 t: Y) p I4 w' e8 y* i) e/ nint xOffset, 字幕的x坐标
" S9 [! ]3 @* G+ AGLint yOffset, 字幕的y坐标' `2 d; T {% W
int numLines, 字幕的行数(较长的字幕为2,一般为1)
1 V/ K6 s B. A: n Sint lineOffset, 这个需要再研究
+ |9 \, X- w5 Y6 @2 O6 [: x8 |int lineHeight, 字体高度(或行高)
6 C& N3 T! y2 W9 c H" l- X) bGLuint displayListBase, 这个字体对应的base值' ]1 g- B3 L. [' l1 a6 V! B
char *text, ... 字符串
f- [7 T. ~) N8 d. y
9 R& y. v5 K8 o& r. X |