本帖最后由 shane007 于 2023-9-5 16:49 编辑
: }9 c7 ] M6 ]
* g5 U$ l) ^; o4 u8 Z这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎. p' {$ T( Q3 j! y! R2 J3 S' M
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
+ I4 v7 X$ G' s+ }$ Ghttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081
% `- f+ W' R. T* l( W# _- A: S第1处
% X7 \ K7 y$ {- void sub_451474(char *a1, ...)
# b$ Z! P3 b2 P2 C8 f7 _: v9 O# ` - {. p! Q3 b" I7 ~
- GLsizei v1; // eax1 q P+ c$ ]1 m$ }! {" G
- char lists; // [esp+4h] [ebp-800h]
2 `# |* o, D* T - va_list va; // [esp+810h] [ebp+Ch]
; N, S0 U; q# Z+ I9 f- ?( b/ {" a
+ w# [$ I, w* }3 o l- T- va_start(va, a1);
% ^) I+ s- |7 u: {$ I6 r - if ( a1 )
7 K( ~& J3 u; _8 h( M* F - {9 a& \8 a: \" @9 l0 o1 @* @; v
- vsprintf(&lists, a1, va);
8 U* _) S9 j: Q/ \) w$ Q4 p - glPushAttrib(0x20000u);, h) w6 l- f! Z7 w- P
- glListBase(base);
5 i1 m9 h/ D- X3 {: X/ h - v1 = strlen(&lists);' O" A$ r' s6 _' a: }2 h% {( j
- glCallLists(v1, 0x1401u, &lists);8 Z* V, `, w/ G
- glPopAttrib();& F% l3 P$ F# c$ H1 w
- }
5 P9 M" k- q2 n; k - }
复制代码 0 d, d6 I6 |! z7 r$ k' n
3 z* M4 r$ ^. P1 g' n
+ w, T9 {) ~+ i6 L, A# n( Z) W! R, b第2处. T8 c# _- Y; P: Q! ]3 U
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
+ M* F3 O- L; d! i - {
. ~+ _* j) {4 {# y; M7 _# g+ d - int v4; // eax
v. `7 I4 N' q - GLsizei v5; // eax
2 p ]) A- |- `& a. C - char lists; // [esp+4h] [ebp-800h]5 `3 W6 l2 P' f k& `& ?
- va_list va; // [esp+81Ch] [ebp+18h]6 }5 A" p, H% ^' q4 b+ {
- - Y4 t: h' q% P4 Z; a* v U
- va_start(va, a4);
5 x4 I7 [% u$ {7 [8 a - if ( a4 )2 P1 i V. S- p: ]
- {
4 g. W7 y/ v; I, ^ - sub_44F8A0(a3);" l' I2 G9 ~& W" m* c( l
- v4 = sub_40BB44();+ w% V0 |; p; c1 l
- glRasterPos2i(x, v4 - a2);
4 u) a2 Y4 Z3 \ - vsprintf(&lists, a4, va);
- O1 m; ]# u# Z. |. \2 \ h c4 i1 V, ] - glPushAttrib(0x20000u);: Y7 `$ o: @; G# F% A5 M9 c1 d. j$ v
- glListBase(base);3 p5 G8 C: n' z. n# Y2 l9 k
- v5 = strlen(&lists);! H2 v8 n- j. Y$ J3 f' ~- I$ d
- glCallLists(v5, 0x1401u, &lists);
$ D ]# m+ E9 l" [ - glPopAttrib();0 d( @9 o: a/ _! k
- }
- g( q' d* ]8 E' @/ `6 p3 T - }
复制代码
% }- V; ]2 \6 I
$ s0 j, a4 U2 x! Q# p+ d, S+ z4 e' }2 _" Z/ r. m
第3处* y/ Z% a1 U5 ?% @; h
- , C" j0 H7 X- y5 c( ^2 O
- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)5 }. x6 _) O# d* c4 G, f
- {7 A; z. Z+ W2 D4 l4 _! Z
- GLvoid *v7; // ST08_43 k: W' ]% R/ |2 I/ c
- GLsizei v8; // eax5 K" m0 C. G8 _) O7 O) I9 y
- int v9; // [esp+0h] [ebp-1018h]& e; l& y% T5 V1 v, N/ H
- char v10; // [esp+8h] [ebp-1010h]
! z) W% U M0 d - GLvoid *lists; // [esp+100Ch] [ebp-Ch]
; i. `+ T- A3 i2 a h1 _, \6 l: ?0 q - char v12[5]; // [esp+1013h] [ebp-5h]
1 P6 a7 L; X9 p6 S& h! t5 _ - va_list va; // [esp+103Ch] [ebp+24h]) n) i: F! n0 t2 Y
" @) f! f$ h2 d! r/ [* x* Y- va_start(va, a7);
8 ?4 J1 i3 `4 m& G - v9 = 1;
( S- w) J0 V9 |! L$ W - if ( a7 )# e; r, _& J6 @, w
- {
" C% c0 k, R. S9 A& o ?: T3 Q! y - vsprintf(&v10, a7, va);* N# A' m- q) v( l3 v( q9 H
- glPushAttrib(0x20000u);
$ ~# k& Q/ ]5 ]4 I, n5 O - glListBase(base);0 X4 L8 s9 i [
- lists = &v10;8 t* g# z: T5 ]2 J$ m- ^2 \: g
- do" i* {6 j9 G) I$ Y! F1 Q8 p& N- V
- {
8 Q9 `0 o) b- h" G$ n - *(_DWORD *)&v12[1] = lists;
/ q/ U4 R6 X+ D& i; Y" L5 E - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )
! l! C$ ]9 R5 K0 Z4 L! a: p - ++*(_DWORD *)&v12[1];) x3 m' }, j g/ z! {
- v12[0] = **(_BYTE **)&v12[1];1 `! j( _7 U/ Q) P8 _
- **(_BYTE **)&v12[1] = 0;
$ `' v8 }: O& z' q, [5 v7 @' c - if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 ), h0 ~' I. q& I( v7 V3 S
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
0 c! V- W4 m1 S8 r. r* _ - y -= a5;
- i) Q# m. {9 t: V; E& \ - glRasterPos2i(*(_DWORD *)a4 + a1, y);
7 z1 E2 |; j) o. W/ h - v7 = lists;
6 `6 Q! Q6 k# K) x; P$ f3 _" o - v8 = strlen((const char *)lists);+ z, C2 t$ K$ u) j5 |2 v# M7 |
- glCallLists(v8, 0x1401u, v7);
% b0 y; |8 q |, l - if ( v9 < a3 )
2 y8 r# O! T: _, ^9 i9 e. ^% w2 O - a4 += 4;
, w+ O4 L( ^/ u7 G( p - ++v9;9 F3 A, C% V7 d$ H# `& [ |
- lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);; A8 {" E* N* e9 H6 k1 m. X: m8 k
- }7 m5 K# a( q7 I8 g/ @ j0 c5 q
- while ( v12[0] );# }* m# F' m9 f$ l
- glPopAttrib();$ m' o' B& N# X- y5 ?
- }( a+ O V8 G* ?. k1 t6 g+ H
- }5 o, _. ^! F! z6 n# j3 y# w
复制代码
, C3 b' m8 D; l* |9 d. k; w调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
a! T0 |" _/ n$ a' Y. a# Z9 b/ p/ L5 m4 b/ z% E
- .text:004512B1 52 push edx ; char *
6 f; n1 L4 L. Y, J. |) b( | - .text:004512B2 8B 45 30 mov eax, [ebp+base]
5 A9 t3 L( i: ?0 O" a1 g8 a3 ^ - .text:004512B5 50 push eax ; base' v V5 H: \3 c- \! j0 O
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
. d; P0 f+ U& p( r( H$ q - .text:004512B9 51 push ecx ; int
* ?' c0 ]( W* g3 X9 L0 J - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]+ d3 P% N9 {% {: A
- .text:004512BD 52 push edx ; int8 q9 s, z# Y! W0 v9 o" K( G/ J
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]
2 r4 t1 U$ B8 O, K! e) B0 u6 i - .text:004512C1 50 push eax ; int" W% n9 g- E' a
- .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
& C* }* q! v" K2 i6 @ - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]; a( \- C" C: [2 r) c4 R( B# x- O
- .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]2 t& K, k! m3 ?* C% X
- .text:004512CB 51 push ecx ; y
" q+ n! X5 L1 l' D; B - .text:004512CC 8B 55 08 mov edx, [ebp+x]8 r) d; r6 X8 }- `
- .text:004512CF 52 push edx ; int9 t( F: |8 T+ \2 E7 }2 w0 B3 s
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 8 [4 S) B* k r& r
chatGPT整理过之后,如下: n p" w9 g2 r3 }9 j" _
l6 k' S6 ?& Q7 b9 w/ G; o7 t! W
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...). D* I1 C- V0 e; w
- {
- q8 D. s8 S: l; s9 f4 f/ s% M - GLvoid *textData; // 存储字符数据的指针
6 y9 s/ s$ j0 h0 a2 S/ h D - GLsizei textLength; // 字符数据的长度
# q7 }+ g0 W) A2 w. T+ ]% ` - int lineIndex; // 行索引
( ]3 C+ H0 j# ]! o, B( f, |# p7 ~! O - char formattedText[5]; // 存储格式化后的字符数据
Q U- {$ A$ q+ n' j% c% i - GLvoid *currentLine; // 当前行的字符数据指针2 Y) [7 H" E8 ?. [$ O
- char buffer[5]; // 字符数据缓冲区
3 l6 l7 P0 z7 {6 a% x8 T - va_list args; // 变长参数列表# x2 {$ y# k8 Y( U8 i; N
- : g. ]8 X# z9 @: k- ]% M3 Y" k! x
- va_start(args, text); // 初始化变长参数列表5 M* {2 V& t* r+ w1 I/ {& y' W
- lineIndex = 1; // 初始化行索引为1
( C7 j, h. ?2 s* ~
. O5 ~6 _0 \/ @( l1 R- if (text) // 如果文本不为空; M0 Q& t8 R1 b4 b5 W* v
- {' h. ]9 q4 _4 i f! p
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中4 j% Y! P; v6 G4 o/ A
- glPushAttrib(0x20000u); // 推送OpenGL属性状态7 ~ r1 [1 a2 a) c+ e
- glListBase(displayListBase); // 设置显示列表的基础值
8 V: M: v- r. o# k2 L/ B% d8 w7 ` - currentLine = formattedText; // 将currentLine指向formattedText的内存位置
7 R1 m6 z: c, h( E9 Y, o$ {6 u
0 H2 {; y! f L- `/ t! J( R; ?/ C8 C- do
) ]0 F" v1 g9 }) l - {
K8 |7 Z3 M2 g4 ^* W5 M - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
8 f T* l0 t8 ]& `( F0 X4 l" r - % |* o4 ~/ x1 i
- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
% n! t: r9 x9 [+ p) u! y: Y# i - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
) u: h) n2 [+ ~! t6 b. n - 8 K& }5 Z9 a, R: ^ U
- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素9 K7 z5 Y4 m2 F! o9 Q
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
+ t) G: N! a" o0 Z5 c; O7 P - ! I. g( H" ~) r$ q" a! w
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)/ G6 e8 F- Z$ m' ?% t: }, f" n/ A
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符6 O5 Z" t0 x4 Z
0 f9 n5 B* H0 I% a4 A- yOffset -= lineHeight; // 更新y坐标( |$ N+ w( O* l- S
- glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置. S- i: _& W# p/ W/ c- z6 Q6 {6 H
- textData = currentLine; // 将textData指向currentLine4 O# ]5 R: F6 J% l+ t2 b9 U9 S
- textLength = strlen((const char *)textData); // 计算字符数据的长度
5 c/ d9 Q) ?! f& y/ a+ y - glCallLists(textLength, 0x1401u, textData); // 调用显示列表) S4 i2 u8 P- E/ ~ I3 [! z, M
- # \' G8 {1 j% J k) L
- if (lineIndex < numLines)
7 X0 w6 I) e+ i$ P& V' @ - lineOffset += 4; // 更新lineOffset4 @% u5 J U3 k7 c- S1 Q+ f
- ++lineIndex; // 递增行索引
0 ?- I4 p& \( Z8 ?5 l# \ P - currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据9 ^5 D: @. l2 M
- }6 `4 J# H- R6 V7 q/ E+ N5 o8 g
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环) ^$ o) `9 n0 h l& Y
- glPopAttrib(); // 恢复OpenGL属性状态8 C' h( Z1 V* |0 U: g4 s
- }5 I! H6 t7 t6 l# G
- }
* t8 J1 l9 h( \! L% k9 r) A$ Z
复制代码
) s/ N% o: H/ J3 }! y含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
( g# ~2 h: F% o5 j$ a
. x# B5 k7 I4 ^& A! ^* yint xOffset, 字幕的x坐标" l: K- |9 [% {6 s1 Y9 X8 w5 }$ \
GLint yOffset, 字幕的y坐标
/ j' g7 T3 e( _8 }- W1 v' Iint numLines, 字幕的行数(较长的字幕为2,一般为1)
3 W1 S3 K( D1 nint lineOffset, 这个需要再研究2 r5 p3 P2 K9 n4 K9 G
int lineHeight, 字体高度(或行高)7 Y8 s) ~, T8 {! v* Z7 P
GLuint displayListBase, 这个字体对应的base值
. S/ d7 L' _# d8 |$ w% W _" nchar *text, ... 字符串5 X1 t3 e9 o$ M! m5 h
, N' n$ P6 R7 u$ v& T4 ]
|