本帖最后由 shane007 于 2023-9-5 16:49 编辑 / C% L! I! e2 z, m$ f/ d. e, e
' Z- E' S! Z: I8 v" I! O这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎9 l" F0 N6 ], N8 q9 M
因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。" P4 M3 V- _) ]4 |/ E8 v
https://www.chinaavg.com/forum.php?mod=viewthread&tid=1540812 L5 Y' m6 a0 Z9 o6 A
第1处
) A4 _& `6 X4 ^; L0 ?- void sub_451474(char *a1, ...)
6 O6 _1 b' e/ _2 S' V1 d/ _ - {( ^' U/ \, z- f( _9 z. v# u: X
- GLsizei v1; // eax
9 y" E, A# i6 k k$ P2 Q- A - char lists; // [esp+4h] [ebp-800h]! z$ Q7 k; h! w* ]3 t; o) H7 ^. F4 I
- va_list va; // [esp+810h] [ebp+Ch]
2 X8 {$ U) z+ T% m9 ?! l5 B - R7 X$ o6 | E$ F& ` u
- va_start(va, a1);9 i9 ^+ m9 d# r# n" f- m5 u
- if ( a1 )3 K& b w. H4 {
- {( O, H( H' t, W; ~( X# L
- vsprintf(&lists, a1, va);. {* Q& c& d1 p+ p& H
- glPushAttrib(0x20000u);
' ?. o: Y2 W. s% A b - glListBase(base);( `" C i" B/ ]; @: Y9 Z3 ^
- v1 = strlen(&lists);4 E* n# c. [7 ?. j D$ u
- glCallLists(v1, 0x1401u, &lists);
- `8 |# ^, I* F7 _3 x5 P, J - glPopAttrib();, ?! g( n3 T- }! ?# I
- }
, D" a" O6 R" o8 k - }
复制代码 : \6 a- R/ y2 x
7 l$ Z* J. t5 U
3 a* C# t0 g( y& M3 H3 e; o第2处
) x- Q( `9 Q# D5 D; E7 P- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
) @! b+ J$ D+ \) U - {
1 [+ n2 p: f$ K6 a* @ - int v4; // eax# ^8 X( z% M% w- m) z8 C( @# D# g0 B
- GLsizei v5; // eax5 D! k- F& z0 |2 p3 @) p8 ]% o
- char lists; // [esp+4h] [ebp-800h]
$ H4 i2 K# D4 s3 y - va_list va; // [esp+81Ch] [ebp+18h]# B; P+ k9 }; h$ g. x8 b9 z0 i
- & P1 a) S# N, @7 l, M z
- va_start(va, a4);8 {5 ~$ A' |. b8 U+ [ G
- if ( a4 )& s% `% v. Y0 x- w, b% d* T$ i) m
- {5 d7 k6 U `. t/ ~1 P! w( l& A
- sub_44F8A0(a3);
% g! q. x( o% d- e3 s - v4 = sub_40BB44();
$ _6 P1 ]: Z' u) D: C; H- { - glRasterPos2i(x, v4 - a2);, v7 o0 }. H$ Z, z* S8 N
- vsprintf(&lists, a4, va);
) K3 g% t8 x% j - glPushAttrib(0x20000u);
$ @6 l5 b9 T+ d6 m - glListBase(base);
. B9 y+ s5 S4 Q. d - v5 = strlen(&lists);
# R) ?# o1 N* ~7 t) k" c! G8 G - glCallLists(v5, 0x1401u, &lists);( F: u$ ~6 P8 t% a3 |
- glPopAttrib();: i% o2 X" [0 X: P0 ]! F
- }5 B Y' ^1 O3 ~6 F
- }
复制代码 # \ ~6 U9 `- M- T
; K% ?$ _9 r/ J m/ ?3 G
5 h( Y" T, Q& E( A" u第3处. k8 H0 x9 I# G7 g2 J8 J
, u0 u2 ^) A1 W7 o7 n. ~( c, ~5 z3 V- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...)/ }* H: m0 A( A4 E$ W# m
- {( z/ Y1 h! Y9 r
- GLvoid *v7; // ST08_4% s4 a. _ j# M( m
- GLsizei v8; // eax
$ k' F- u7 i1 d3 o U - int v9; // [esp+0h] [ebp-1018h]
2 ?# p. Q0 x6 F+ i - char v10; // [esp+8h] [ebp-1010h]4 q- a2 X3 p/ d! h" D
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]
1 E7 c1 H4 v! ]- x - char v12[5]; // [esp+1013h] [ebp-5h], g0 }3 g! W5 T1 c: o; V u5 l
- va_list va; // [esp+103Ch] [ebp+24h]
( Y) U4 n' f' g
- V+ [1 J9 w* h1 H7 l- va_start(va, a7);1 L; o8 H! c3 H0 Z# f
- v9 = 1;7 `* Z* X: ~; h
- if ( a7 )# t5 B+ c9 C5 E" ~3 d) z& j
- {
2 w% i, ?( @3 L5 w - vsprintf(&v10, a7, va);
5 e4 z( R1 h$ ?* \% C- { - glPushAttrib(0x20000u);
: O# N' I0 Z% y1 F! ? - glListBase(base);
; n" q. N- P# ^* Z* h3 @7 q Q* o - lists = &v10;
; g6 u/ L) m. r2 `2 s$ C+ ~ - do
" n d- T/ b7 F% }. c: J# G; p4 b - {
( m/ X9 f; s f! [ - *(_DWORD *)&v12[1] = lists;
2 P. i& X1 k& _3 f% b/ w, [ - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )2 F/ I6 L5 |" P
- ++*(_DWORD *)&v12[1];" a p; {' \+ L# V" M6 C5 J
- v12[0] = **(_BYTE **)&v12[1];
* A, U7 q7 y/ M# s6 A2 `% q - **(_BYTE **)&v12[1] = 0;" l1 F' |8 C. t6 G
- if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 ) x- [+ D J4 S. t
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;
" i" s8 V4 J) k) { - y -= a5;
: k3 \3 _9 s0 g# {; b - glRasterPos2i(*(_DWORD *)a4 + a1, y);) T3 A% ^9 U9 H
- v7 = lists;
' t; g! {9 t( J( V* x0 _ - v8 = strlen((const char *)lists);4 Z8 Z2 l* C5 l# }
- glCallLists(v8, 0x1401u, v7);
- A# r$ [) B+ N! b- \4 k& N: K - if ( v9 < a3 )
% A! W4 d! Q2 j - a4 += 4;, ?$ s1 u( {) o
- ++v9;0 T0 [' \$ p& C; h4 U
- lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);
! ~; T) @. ^+ ?5 a# n# A - }, e. _+ v, G% i5 ~5 @/ t1 E
- while ( v12[0] );
" M8 w1 \+ Q! ^+ V+ ?6 N6 M - glPopAttrib();
- F: r0 v6 q: A, ` - }
! R8 ?; S- B; a2 s0 D$ D - }) K" S3 d/ E7 P, v3 A
复制代码 # h2 m3 {8 s" e; x4 I) {2 ?2 H4 L% a
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810, o# f* v2 g% e) P! v1 D$ \3 f
4 ?0 u) ?$ v/ p! E5 J2 L% l+ M* R- .text:004512B1 52 push edx ; char *% | ^: T( h( E8 Z( x+ J
- .text:004512B2 8B 45 30 mov eax, [ebp+base]
2 }! ^2 H1 C4 @. k9 S7 f1 S9 R - .text:004512B5 50 push eax ; base) z8 ~8 T0 Y: q) E
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]
! M$ u$ _- ]) r% | - .text:004512B9 51 push ecx ; int
$ u; g; N4 U, n0 T/ J c - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]- t- v$ F7 z b0 I
- .text:004512BD 52 push edx ; int9 e8 w% r- v1 X# q1 X) c6 U% i2 K9 q
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]0 E1 s; J7 h; y- f8 @6 W
- .text:004512C1 50 push eax ; int
+ e9 Q. S5 G' w - .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
+ E/ w1 S' } E - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]
: S: Q, d: A9 t - .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C], v2 w+ I* y9 ^3 k' c/ m* P; a
- .text:004512CB 51 push ecx ; y
7 b$ f+ W7 G, S' i& M1 ]+ h: G6 Q - .text:004512CC 8B 55 08 mov edx, [ebp+x]
8 |' M! W8 R* U - .text:004512CF 52 push edx ; int- l% ?& N1 Z! E
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码
9 \- @2 Y$ ~* H, c& A) Q& J& \5 ]$ @chatGPT整理过之后,如下
9 k! D8 }0 A D" u. [# v" `# s- Q" D/ U
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)
1 c, ~0 R6 u3 x5 c/ g. A - {
6 d; n( m0 M9 ]! B; v- U; Q - GLvoid *textData; // 存储字符数据的指针
+ w( n) i+ A2 [( ^9 p - GLsizei textLength; // 字符数据的长度: m5 o2 o+ ?7 w5 I: |6 n
- int lineIndex; // 行索引
$ j' c( i( P' L/ d7 }2 G$ @$ ^ - char formattedText[5]; // 存储格式化后的字符数据
! Y9 B7 F9 W X1 I8 |" _ - GLvoid *currentLine; // 当前行的字符数据指针
& Z. C# T: t1 n9 X& r; e) T% z - char buffer[5]; // 字符数据缓冲区! P! w' t" r3 n9 y
- va_list args; // 变长参数列表" x1 Z- {. E# a1 w* K2 } p& W
- 3 f: q. W* ~( }) B: @
- va_start(args, text); // 初始化变长参数列表, n! o+ V0 g- p4 b7 z
- lineIndex = 1; // 初始化行索引为19 h( p- s8 J |! K+ `, i
) {0 W3 ]1 t5 S/ T- l2 b- if (text) // 如果文本不为空8 d! s4 m. S! l
- {; `9 P% y. g: P0 Q3 v/ X( f" V, R/ q
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中( f- U8 J8 U4 o: w& {
- glPushAttrib(0x20000u); // 推送OpenGL属性状态
- x( y0 h) O0 c, r8 }- T - glListBase(displayListBase); // 设置显示列表的基础值
# \, H1 p" @/ B# h+ Q# T8 w - currentLine = formattedText; // 将currentLine指向formattedText的内存位置
5 \' R# E: v* x- J
" g* K) U7 n5 u, C, H- do
& d2 t% \( H) ^4 c- y* S3 g7 H, l - {' R" [+ x- G% [" `
- *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
: I/ p: T! n, |$ I( N3 f( r& B
' ^ `4 Y) x/ y- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束; f1 J2 l i. B; W- b/ f, L+ R! G( e
- ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素8 a; e7 T' N: J$ H
( s3 t9 c* f( w1 q% S% u% @% V- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素/ B* S9 k3 B! i3 M# o
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符6 `5 c: I& J8 e8 y* L b9 X. w6 S
- 1 P3 s& C; f0 r( r6 s8 {9 K3 b( L4 f
- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)
0 j0 C. O% G: }& y2 m" g - *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符
/ }7 a4 ^, x0 M0 C& D - 9 M% w: Z- u0 p A6 f
- yOffset -= lineHeight; // 更新y坐标
- _; w$ Y ], w - glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置1 _" U0 l5 | e% L4 Y& Z
- textData = currentLine; // 将textData指向currentLine
1 v- r& y% p# w% d3 K - textLength = strlen((const char *)textData); // 计算字符数据的长度
. M- O& N1 o( T0 G) x& N - glCallLists(textLength, 0x1401u, textData); // 调用显示列表
' f% }% L5 D* m' \0 S3 l/ ?
: u8 P, p) ?# a; L, \( q- I) N- if (lineIndex < numLines)
: O# |# R, r- w3 l5 G - lineOffset += 4; // 更新lineOffset
: m5 R; Z+ i% U$ M% [/ } ]5 N - ++lineIndex; // 递增行索引& [7 k( f. O8 r' C: I- |
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
) X b0 p( f7 N8 {1 p5 v8 j+ ? - }
3 k& |1 y4 T! y: w6 ~7 u - while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环0 k* m% Z) f7 R
- glPopAttrib(); // 恢复OpenGL属性状态
1 [5 T, @1 K* ]2 C( V+ E - }
" U6 t/ I- f! C8 {. ? - }
4 |8 W4 {1 d5 q6 e" J
复制代码 & a! V# I% R1 {/ L8 j3 C3 I8 p( N+ P! A
含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
" l% A' ~0 n1 o& S2 F, x( z# n, p, N/ p9 a! E
int xOffset, 字幕的x坐标
' E+ x3 C; K$ Z f4 UGLint yOffset, 字幕的y坐标
8 \4 r: D% m" T9 X- Y) `$ L1 J3 i. [. Yint numLines, 字幕的行数(较长的字幕为2,一般为1)
0 Q5 z" Y4 V/ ~1 I, Mint lineOffset, 这个需要再研究
3 ?/ `1 X$ \% C0 }/ G6 {6 N O- wint lineHeight, 字体高度(或行高)
" C" Z7 b: p9 s! yGLuint displayListBase, 这个字体对应的base值
' a6 {) O" d; w$ P& mchar *text, ... 字符串6 s' I9 c% m+ {, h" C1 d4 |
& Q" A( M: s& l7 D |