本帖最后由 shane007 于 2023-9-5 16:49 编辑 & s6 T; m8 K( r6 x( _0 [: @0 X1 P5 p
5 e: w) h& _% t8 U, ]这个游戏也是opengl的游戏,本游戏的和魔法英雄历险记(Tale of a Hero)这个游戏用的是同一个引擎
8 @" y* z7 M& R* D! Z5 r, F因此代码基本类似,对glGenLists的调用处也是6处,因此参照以上帖子即可。
1 P/ K- q+ y3 X' n# k5 xhttps://www.chinaavg.com/forum.php?mod=viewthread&tid=154081' z& x# {; }/ T: l
第1处& ?- d, ?! b/ f0 L" b
- void sub_451474(char *a1, ...)0 D( D. C2 A* k: g& |( I
- {
1 |: I M9 U: } - GLsizei v1; // eax
. B/ E; b: J+ |( n! a4 S - char lists; // [esp+4h] [ebp-800h]% |/ A: Y% x' C9 y9 f. E1 y% |
- va_list va; // [esp+810h] [ebp+Ch]
( B6 j4 t6 \4 ^. i. z( N- w7 s
1 l4 Z% o$ z* w: T6 E* n+ K. I: T- va_start(va, a1);
% c1 e* o- V+ L& u - if ( a1 )/ P/ u1 i, p2 o1 D
- {: t4 ?0 B1 D1 M8 n
- vsprintf(&lists, a1, va);
5 H/ X4 ^7 b2 u! K; D1 q - glPushAttrib(0x20000u);
( L: O9 }5 N8 n1 Q9 B- y - glListBase(base);
- h, U' \* n+ z1 l- [0 T - v1 = strlen(&lists); `, A: F8 V$ s$ j
- glCallLists(v1, 0x1401u, &lists);
& v) [( G7 W1 X - glPopAttrib();' f4 g0 Q5 B1 j* L9 L
- }, m o+ ?/ R$ A' M; R/ z
- }
复制代码 9 O4 c* b% r% m5 p# r3 Q
4 ?8 b' D4 k% c, c7 p1 S4 ~
# o. |- G& p. K2 r第2处. E4 y3 A3 }" X( z3 ]) r C* ?
- void sub_4514F6(GLint x, int a2, int a3, char *a4, ...)
# [3 o: x* b: f* J' \ - {
2 }) p& R' F4 Z5 h; @' f! W; O - int v4; // eax
( ~" Y& X G6 P7 w - GLsizei v5; // eax' K5 r( k+ V5 T3 L
- char lists; // [esp+4h] [ebp-800h]
) l7 k5 d* y2 S' b4 c - va_list va; // [esp+81Ch] [ebp+18h]* U7 o! K; K- t5 n* I) B$ @
; W0 v( U$ z2 F5 M. ~6 t- ?- va_start(va, a4);
& G/ |: P; S3 Q7 P: c0 s' G" \ - if ( a4 )
9 T5 N1 N+ l1 z3 \$ A# ~: Z' [ - {
1 P$ { z# k$ e9 G1 h - sub_44F8A0(a3);
5 e1 A4 t/ {6 r9 l - v4 = sub_40BB44();
; W& b4 x% \* p. f4 ]" W - glRasterPos2i(x, v4 - a2);
. I$ L3 |4 J' r) M& v - vsprintf(&lists, a4, va);. l1 L- y- t5 a$ ^9 ]2 }
- glPushAttrib(0x20000u);
( y; }4 L r9 x0 P' W, K& l - glListBase(base);+ \7 C f* O- O1 t" x
- v5 = strlen(&lists);
; h: b; U& T4 h: S+ ?8 j - glCallLists(v5, 0x1401u, &lists);* e3 J: w' R8 S6 ?' [ e& [
- glPopAttrib();, S- y8 j7 F% J2 ~$ I
- }5 v6 E1 |0 `( j8 y6 `( }8 q
- }
复制代码 " I4 V q- z/ J4 E6 J
) z( h d' C% l6 [% M9 y& Z
. y7 L7 s& c* L2 X: P8 @
第3处9 c: i _* ]0 t- |
# |5 o" {( y9 Z3 M0 Z& m$ e- void sub_451810(int a1, GLint y, int a3, int a4, int a5, GLuint base, char *a7, ...) p2 S; }7 p0 J o
- {9 A6 h: G5 }3 t
- GLvoid *v7; // ST08_4
* J( @' z: P- q1 E% [$ Q$ f - GLsizei v8; // eax
/ {+ K( c0 q; a5 k, Q/ | N - int v9; // [esp+0h] [ebp-1018h]+ ?* e5 b7 _) N4 \" v
- char v10; // [esp+8h] [ebp-1010h]6 w3 y* T# H- [2 y$ X" p4 j
- GLvoid *lists; // [esp+100Ch] [ebp-Ch]
5 c t0 G; b3 Y) L8 s - char v12[5]; // [esp+1013h] [ebp-5h]: X H7 F- E" J$ a: v
- va_list va; // [esp+103Ch] [ebp+24h]
1 b7 U3 d; p4 z( ~3 ? - 0 |: H* \( w- Y ^' F# H1 B
- va_start(va, a7);
0 q$ B: m* i& K: d1 z, R9 t - v9 = 1;6 z; Z- M0 U# g _/ e1 Z
- if ( a7 )& ~0 m5 F' V, _0 Z% p! Q% X! j
- {. {- f# C$ y+ ^5 F6 q
- vsprintf(&v10, a7, va);0 G0 ]! y2 _2 Q
- glPushAttrib(0x20000u);
5 k% b7 t) a1 t9 i) [( J - glListBase(base);
& @- s! P0 U t! ^5 V- [& F/ V, u: n - lists = &v10;
* K9 n, a% k `% F - do& Q/ c T7 \+ O' P+ _; R3 p) B r
- {
+ @5 B6 z$ Z$ H: S9 \0 E4 X - *(_DWORD *)&v12[1] = lists;
8 e+ G4 e' I1 h' Y8 | - while ( **(_BYTE **)&v12[1] && **(_BYTE **)&v12[1] != 10 )! t6 _6 N2 x* o d9 y8 p7 H
- ++*(_DWORD *)&v12[1];
( n6 k" G6 G+ [8 V - v12[0] = **(_BYTE **)&v12[1];
* t4 k7 S. q: F( ^8 s - **(_BYTE **)&v12[1] = 0;
( x" G* G, c8 t4 \: o' p# x - if ( v12[0] == 10 && *(GLvoid **)&v12[1] != lists && *(_BYTE *)(*(_DWORD *)&v12[1] - 1) == 13 )- n" S8 T& | V' @4 c# n
- *(_BYTE *)(*(_DWORD *)&v12[1] - 1) = 0;4 M! x% }0 h6 j$ b! V) |
- y -= a5;
' N% Y1 ?& e/ }" e2 R$ ~1 y# O - glRasterPos2i(*(_DWORD *)a4 + a1, y);& _ b4 Y4 I! z% |) N1 {
- v7 = lists;
; c- E1 d& f7 }! K5 O - v8 = strlen((const char *)lists);
" O7 D9 G! u1 d" t3 l- f6 x' o - glCallLists(v8, 0x1401u, v7);
( w$ m3 x, v; F9 ?9 ^* j - if ( v9 < a3 ) ?( l( }* q4 m/ A) {
- a4 += 4;+ T# P4 o) L! E5 [; ?
- ++v9;
3 \* k) d7 ? J, g V - lists = (GLvoid *)(*(_DWORD *)&v12[1] + 1);/ g: ] j3 r; N: x3 Q9 ~6 m
- }9 Y; K! q' Z, P9 h
- while ( v12[0] );3 `5 Z& a- L& r y( n y, o9 Z9 P
- glPopAttrib();6 x9 }5 | b6 B9 H% w
- }# G1 ?0 P) U8 `2 L. D6 o
- }
4 d2 W1 [; E. r( k
复制代码 0 p. z7 n$ g! E6 n( h2 l
调用处,将 这句nop掉之后,游戏对话字幕不显示,因此,451810是对话显示函数。.text:004512D0 E8 3B 05 00 00 call sub_451810
2 S: U' { E9 g, F, V" a3 S0 w% v1 u
" L7 ]' b( D. w( ^- .text:004512B1 52 push edx ; char *
2 x7 I$ Y, |! x0 r$ Q: Q - .text:004512B2 8B 45 30 mov eax, [ebp+base]
+ ]9 R' B8 q+ J; z) c# X' _2 t$ I - .text:004512B5 50 push eax ; base4 f+ M1 m. `- Z0 U
- .text:004512B6 8B 4D 20 mov ecx, [ebp+arg_18]1 m9 ]4 K& {* k& U3 f- E% M
- .text:004512B9 51 push ecx ; int
; _9 e% E" \, u! j2 ?, S - .text:004512BA 8B 55 1C mov edx, [ebp+arg_14]
# K9 r5 [1 a8 i" U - .text:004512BD 52 push edx ; int" m2 L- @0 S# v3 k: Q) B. K
- .text:004512BE 8B 45 18 mov eax, [ebp+arg_10]9 Y [2 x" t: C# `3 a2 w
- .text:004512C1 50 push eax ; int/ [5 k* W% J; u" {7 Q
- .text:004512C2 8B 4D 0C mov ecx, [ebp+y]
6 `. M5 ?9 w- Z6 Q4 @- j - .text:004512C5 03 4D 14 add ecx, [ebp+arg_C]; z0 n. z: l* `. G5 f4 d
- .text:004512C8 03 4D 24 add ecx, [ebp+arg_1C]. I" C2 u' T* N2 l$ D
- .text:004512CB 51 push ecx ; y
2 d* n2 M5 B3 ~- l( y8 z - .text:004512CC 8B 55 08 mov edx, [ebp+x]
6 q) E* M& y, e4 y - .text:004512CF 52 push edx ; int% J, N k# P, ^. f% r9 K. D3 u5 l" X
- .text:004512D0 E8 3B 05 00 00 call sub_451810
复制代码 1 q1 y5 b+ q& E, l+ G
chatGPT整理过之后,如下$ v, L6 e9 ? o6 k
- I, m. e/ U6 O% M% w
- void renderText(int xOffset, GLint yOffset, int numLines, int lineOffset, int lineHeight, GLuint displayListBase, char *text, ...)" N% O/ B, `# o9 P4 a: R8 g) X
- {& U; r7 f& ~1 {
- GLvoid *textData; // 存储字符数据的指针! M+ b$ ~, \. F }. a
- GLsizei textLength; // 字符数据的长度5 [, {# q. l+ i: U) P
- int lineIndex; // 行索引! l3 o4 V+ E1 Y; t) ?) V
- char formattedText[5]; // 存储格式化后的字符数据" z% ~, G" C! o& p/ ?6 L5 h* D' O
- GLvoid *currentLine; // 当前行的字符数据指针1 ]- X; y6 }1 |; M0 P$ a
- char buffer[5]; // 字符数据缓冲区
" p' k/ Y2 s8 Y5 j0 e% O$ U - va_list args; // 变长参数列表$ A1 C( {( d0 u; b* m5 X2 K' K/ n
- 8 d& F0 ?" z, l$ Q
- va_start(args, text); // 初始化变长参数列表
" B* ]4 @2 j1 ] - lineIndex = 1; // 初始化行索引为1
6 V4 D8 Q: q) S$ P& B
k B c1 N! }5 B% M* Q" i. n: d' S- if (text) // 如果文本不为空! z. p6 l+ }. A
- {* z" E/ i! J/ u+ d1 t; ]
- vsprintf(formattedText, text, args); // 使用变长参数列表格式化字符串,并将结果存储到formattedText中/ n) w# Z; S: R7 q4 h& B/ p9 B
- glPushAttrib(0x20000u); // 推送OpenGL属性状态9 L& t9 k8 k5 ^* K# o4 {
- glListBase(displayListBase); // 设置显示列表的基础值& W. v2 i. {& B4 R1 Q+ y, Z
- currentLine = formattedText; // 将currentLine指向formattedText的内存位置. j) _ H& D& ?; r- L
- + p- ]1 m2 S Q5 D: ?& h: c! X4 j
- do; c+ o- i5 t, \3 t$ X/ d/ G
- {
$ V0 A, I3 Q; ]5 T& D - *(_DWORD *)&buffer[1] = currentLine; // 将currentLine的内存地址存储到buffer数组的第二个元素
# w( T: g- G% p
4 ~- {/ W8 J" X/ N- while (**(_BYTE **)&buffer[1] && **(_BYTE **)&buffer[1] != 10) // 循环直到遇到换行符或字符串结束
" r. A' N9 ?; p8 y - ++*(_DWORD *)&buffer[1]; // 递增buffer数组的第二个元素
+ t3 Q: e3 v ?+ L6 u0 g& ]
+ S; f$ s0 K% N$ F- buffer[0] = **(_BYTE **)&buffer[1]; // 将换行符存储到buffer数组的第一个元素: ?8 P5 u0 c n- C) `
- **(_BYTE **)&buffer[1] = 0; // 将换行符替换为字符串结束符
! ]8 y+ x* R3 B. m$ g" W" @
* \' [% v! l; C9 v$ V" L# v- if (buffer[0] == 10 && *(GLvoid **)&buffer[1] != currentLine && *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) == 13)! _. L7 ^2 Z5 J! g- L
- *(_BYTE *)(*(_DWORD *)&buffer[1] - 1) = 0; // 处理换行符和回车符6 L: [2 l$ N0 f( ^+ X( V
- ; ?. E+ J+ I" F! ^7 t2 J
- yOffset -= lineHeight; // 更新y坐标
4 T5 O: r* p9 p P4 a( R- L0 v: O - glRasterPos2i(*(_DWORD *)lineOffset + xOffset, yOffset); // 设置光栅化位置 }) F! }$ M+ J+ ^- p$ i
- textData = currentLine; // 将textData指向currentLine
7 o# I1 K+ x; r: Z+ U - textLength = strlen((const char *)textData); // 计算字符数据的长度
4 [! Z# c8 w) }8 S/ c - glCallLists(textLength, 0x1401u, textData); // 调用显示列表
' ~# T$ O1 Y. N2 P3 Z, m; O2 s( y7 w
) w+ z5 O5 O) F. a: t4 r8 K- if (lineIndex < numLines)/ F! e% p0 q! h+ a; G* ]$ x
- lineOffset += 4; // 更新lineOffset
# Y8 [4 y5 |3 }4 U: h; ?. W - ++lineIndex; // 递增行索引) N9 R$ C5 n X/ E- }1 S3 J
- currentLine = (GLvoid *)(*(_DWORD *)&buffer[1] + 1); // 更新currentLine指向下一个字符数据
; `9 Y) \- ^0 p% q - }* [# W9 E! D: q! ?
- while (buffer[0]); // 当字符数组buffer的第一个元素不为0时继续循环, |. p7 _4 ?. } N/ Y1 ?
- glPopAttrib(); // 恢复OpenGL属性状态. _, ^5 ] W# I
- }
; K& {) g3 g, b. }% C; Q' u, ~& ` - }
; k' J& F- ]- }" P' W
复制代码
9 E# Q2 |$ \ E0 N含义解释如下,设置字符串颜色还需要寻找,也许是在调用此方法之前
% l: f" W% Y/ \. I
/ V) [6 [/ E6 y: u) \- j4 z4 hint xOffset, 字幕的x坐标
/ }2 t* S' e+ ?- s4 v& [GLint yOffset, 字幕的y坐标
) I j4 k: A/ `6 i0 D8 \- ]# D4 j5 |, jint numLines, 字幕的行数(较长的字幕为2,一般为1): g# t% Y% W7 l! ^4 i
int lineOffset, 这个需要再研究
. e2 z( p. X" W/ ~& p. uint lineHeight, 字体高度(或行高)
{: O0 q1 O" p; F! |/ jGLuint displayListBase, 这个字体对应的base值7 [$ d7 i& I) n9 ^
char *text, ... 字符串; ]9 Z) ]# t6 v# e. n8 `7 j7 w
: c! N* _1 i& j, [' }! S R
|