From 9ae4f7726e4a4ba9532cbb1eb862d590526ed3fd Mon Sep 17 00:00:00 2001 From: nmlgc Date: Thu, 25 Nov 2021 15:58:22 +0100 Subject: [PATCH] [Decompilation] [th05] EMS / Dialog: Face loading and rendering Aha! TH05 actually loads every single rendered dialog image individually before rendering it, either from the EMS area or disk. That's one way to save memory, I guess? Part of P0169, funded by Blue Bolt. --- Makefile.mak | 2 +- th04/sprites/main_cdg.h | 8 +++ th04/sprites/main_cdg.inc | 2 - th05/dialog.cpp | 1 + th05/formats/tx2.hpp | 5 ++ th05/main/dialog/dialog.cpp | 67 +++++++++++++++++++++ th05/main/dialog/dialog.hpp | 15 +++++ th05/shiftjis/fns.hpp | 11 ++-- th05_main.asm | 114 ++++-------------------------------- 9 files changed, 114 insertions(+), 111 deletions(-) create mode 100644 th05/dialog.cpp create mode 100644 th05/formats/tx2.hpp create mode 100644 th05/main/dialog/dialog.cpp create mode 100644 th05/main/dialog/dialog.hpp diff --git a/Makefile.mak b/Makefile.mak index 3d763731..bcef5edb 100644 --- a/Makefile.mak +++ b/Makefile.mak @@ -149,7 +149,7 @@ bin\th05\op.exe: th05\op010.cpp bin\th05\op.obj th05\op011.cpp th05\m_char.cpp b $** | -bin\th05\main.exe: bin\th05\main.obj bin\th04\slowdown.obj th05\ems.cpp bin\th05\cfg_lres.obj th05\main010.cpp th05\main011.cpp th05\p_common.cpp th05\p_reimu.cpp th05\p_marisa.cpp th05\p_mima.cpp th05\p_yuuka.cpp bin\th05\player.obj bin\th05\hud_bar.obj bin\th05\scoreupd.obj th05\main013.cpp bin\th04\player_p.obj th05\main014.cpp th05\player_a.cpp bin\th05\bullet_1.obj th05\bullet_c.cpp bin\th03\vector2.obj bin\th03\hfliplut.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_mode.obj bin\th05\bullet.obj bin\th04\cdg_p_na.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th05\cdg_put.obj bin\th04\exit.obj bin\th05\vector.obj bin\th05\snd_load.obj bin\th05\snd_kaja.obj bin\th05\initmain.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th04\scrolly3.obj bin\th04\motion_3.obj th05\main031.cpp th05\gather.cpp th05\main032.cpp th05\bullet_u.cpp th05\main034.cpp th05\main035.cpp +bin\th05\main.exe: bin\th05\main.obj bin\th04\slowdown.obj th05\ems.cpp bin\th05\cfg_lres.obj th05\main010.cpp th05\dialog.cpp th05\main011.cpp th05\p_common.cpp th05\p_reimu.cpp th05\p_marisa.cpp th05\p_mima.cpp th05\p_yuuka.cpp bin\th05\player.obj bin\th05\hud_bar.obj bin\th05\scoreupd.obj th05\main013.cpp bin\th04\player_p.obj th05\main014.cpp th05\player_a.cpp bin\th05\bullet_1.obj th05\bullet_c.cpp bin\th03\vector2.obj bin\th03\hfliplut.obj bin\th04\snd_pmdr.obj bin\th04\snd_mmdr.obj bin\th04\snd_mode.obj bin\th05\bullet.obj bin\th04\cdg_p_na.obj bin\th04\snd_se_r.obj bin\th04\snd_se.obj bin\th05\cdg_put.obj bin\th04\exit.obj bin\th05\vector.obj bin\th05\snd_load.obj bin\th05\snd_kaja.obj bin\th05\initmain.obj bin\th05\input_s.obj bin\th05\inp_h_w.obj bin\th05\frmdelay.obj bin\th04\cdg_load.obj bin\th04\scrolly3.obj bin\th04\motion_3.obj th05\main031.cpp th05\gather.cpp th05\main032.cpp th05\bullet_u.cpp th05\main034.cpp th05\main035.cpp $(CC) $(CFLAGS) $(LARGE_LFLAGS) -3 -Z -DGAME=5 -DBINARY='M' -nbin\th05\ -eMAIN.EXE @&&| $** | diff --git a/th04/sprites/main_cdg.h b/th04/sprites/main_cdg.h index 7353d39b..8ec82a23 100644 --- a/th04/sprites/main_cdg.h +++ b/th04/sprites/main_cdg.h @@ -27,6 +27,14 @@ typedef enum { CDG_PER_STAGE, CDG_FACESET_PLAYCHAR, + #if (GAME == 5) + // TH05 only uses the CDG_FACESET_PLAYCHAR and CDG_FACESET_BOSS ranges + // as temporary storage for EMS area preloading. During in-game dialog, + // every single rendered face image is individually loaded to this one + // slot, either from the EMS area or from disk, and then immediately + // freed. + CDG_DIALOG_FACE = CDG_FACESET_PLAYCHAR, + #endif CDG_FACESET_PLAYCHAR_last = (CDG_FACESET_PLAYCHAR + (FACESET_PLAYCHAR_COUNT - 1)), CDG_FACESET_BOSS, CDG_FACESET_BOSS_last = (CDG_FACESET_BOSS + (FACESET_BOSS_COUNT - 1)), diff --git a/th04/sprites/main_cdg.inc b/th04/sprites/main_cdg.inc index 4642dfda..5c9a8cd9 100644 --- a/th04/sprites/main_cdg.inc +++ b/th04/sprites/main_cdg.inc @@ -10,8 +10,6 @@ FACE_H = 128 CDG_BG_PLAYCHAR_BOMB = 0 CDG_PER_STAGE = 1 -CDG_FACESET_PLAYCHAR = 2 -CDG_FACESET_PLAYCHAR_last = (CDG_FACESET_PLAYCHAR + (FACESET_PLAYCHAR_COUNT - 1)) CDG_FACESET_BOSS = 8 CDG_FACESET_BOSS_last = (CDG_FACESET_BOSS + (FACESET_BOSS_COUNT - 1)) CDG_BG_BOSS = 16 diff --git a/th05/dialog.cpp b/th05/dialog.cpp new file mode 100644 index 00000000..1bb87469 --- /dev/null +++ b/th05/dialog.cpp @@ -0,0 +1 @@ +#include "th05/main/dialog/dialog.cpp" diff --git a/th05/formats/tx2.hpp b/th05/formats/tx2.hpp new file mode 100644 index 00000000..9a0e1a87 --- /dev/null +++ b/th05/formats/tx2.hpp @@ -0,0 +1,5 @@ +/// TH05 in-game dialog script format +/// --------------------------------- + +const uint8_t FACE_NONE = 0xFF; +/// --------------------------------- diff --git a/th05/main/dialog/dialog.cpp b/th05/main/dialog/dialog.cpp new file mode 100644 index 00000000..72116f73 --- /dev/null +++ b/th05/main/dialog/dialog.cpp @@ -0,0 +1,67 @@ +#pragma option -zPmain_01 + +extern "C" { +#include +#include "platform.h" +#include "pc98.h" +#include "planar.h" +#include "master.hpp" +#include "th02/hardware/frmdelay.h" +#include "th03/formats/cdg.h" +#include "th04/main/playfld.hpp" +} +#include "th04/main/stage/stage.hpp" +#include "th04/sprites/main_cdg.h" +#include "th04/main/ems.hpp" +#include "th05/chars.h" +#include "th05/formats/tx2.hpp" +#include "th05/shiftjis/fns.hpp" +#include "th05/main/dialog/dialog.hpp" + +extern char faceset_boss_format[]; +extern char faceset_playchar_format[]; + +void pascal near dialog_face_load_unput_put_free_8( + screen_x_t left, vram_y_t top, int face_id +) +{ + size_t size; + uint32_t offset; + char near *faceset_fn = faceset_boss_format; + char near *faceset_playchar_fn = faceset_playchar_format; + + if(face_id != FACE_NONE) { + if(Ems) { + if(dialog_side == DIALOG_SIDE_PLAYCHAR) { + offset = EMS_FACESET_PLAYCHAR_OFFSET; + } else { + offset = EMS_FACESET_BOSS_OFFSET; + } + size = cdg_slots[CDG_DIALOG_FACE].bitplane_size; + offset += (face_id * size * (PLANE_COUNT + 1)); + allocate_and_load_from_ems( + cdg_slots[CDG_DIALOG_FACE].seg_alpha(), offset, size + ); + offset += size; + size *= PLANE_COUNT; + allocate_and_load_from_ems( + cdg_slots[CDG_DIALOG_FACE].seg_colors(), offset, size + ); + offset += size; + } else { + if(dialog_side != DIALOG_SIDE_PLAYCHAR) { + faceset_fn[3] = ('0' + stage_id); + } else { + faceset_fn = faceset_playchar_fn; + faceset_fn[3] = ('0' + playchar); + } + cdg_load_single(CDG_DIALOG_FACE, faceset_fn, face_id); + } + } + frame_delay(1); + dialog_face_unput_8(left, top); + if(face_id != FACE_NONE) { + cdg_put_8(left, top, CDG_DIALOG_FACE); + cdg_free(CDG_DIALOG_FACE); + } +} diff --git a/th05/main/dialog/dialog.hpp b/th05/main/dialog/dialog.hpp new file mode 100644 index 00000000..7dfdbd99 --- /dev/null +++ b/th05/main/dialog/dialog.hpp @@ -0,0 +1,15 @@ +#include "th04/main/dialog/dialog.hpp" + +// Dialog-related image functions with optional EMS support +// -------------------------------------------------------- + +// Loads the face image at the given ID for the current [dialog_side] from +// either the EMS area or disk, then calls dialog_face_unput_8([left], [top]), +// blits the loaded image to the same position, and frees it again. +// Can also just unblit the face image without blitting a new one by setting +// [face_id] to FACE_NONE, if you don't like calling dialog_face_unput_8() +// directly for whatever reason. +void pascal near dialog_face_load_unput_put_free_8( + screen_x_t left, vram_y_t top, int face_id +); +// -------------------------------------------------------- diff --git a/th05/shiftjis/fns.hpp b/th05/shiftjis/fns.hpp index 637d163f..e50cc932 100644 --- a/th05/shiftjis/fns.hpp +++ b/th05/shiftjis/fns.hpp @@ -1,9 +1,10 @@ #define EYECATCH_FN "eye.cdg" -#define FACESET_REIMU_FN "KAO0.cd2" -#define FACESET_MARISA_FN "KAO1.cd2" -#define FACESET_MIMA_FN "KAO2.cd2" -#define FACESET_YUUKA_FN "KAO3.cd2" +#define FACESET_PLAYCHAR_FORMAT "KaO0.cD2" +#define FACESET_REIMU_FN "KAO0.cd2" +#define FACESET_MARISA_FN "KAO1.cd2" +#define FACESET_MIMA_FN "KAO2.cd2" +#define FACESET_YUUKA_FN "KAO3.cd2" #define main_cdg_load_faceset_playchar() { \ switch(playchar) { \ @@ -21,3 +22,5 @@ break; \ } \ } + +#define FACESET_BOSS_FORMAT "BsS0.cD2" diff --git a/th05_main.asm b/th05_main.asm index c19e625f..1e9f679c 100644 --- a/th05_main.asm +++ b/th05_main.asm @@ -38,7 +38,7 @@ include th05/main/enemy/enemy.inc extern _strlen:proc .seq -main_01 group SLOWDOWN_TEXT, ma_TEXT, EMS_TEXT, mai_TEXT, CFG_LRES_TEXT, main_TEXT, main__TEXT, main_0_TEXT, PLAYER_P_TEXT, main_01_TEXT +main_01 group SLOWDOWN_TEXT, ma_TEXT, EMS_TEXT, mai_TEXT, CFG_LRES_TEXT, main_TEXT, main__TEXT, main_0_TEXT, DIALOG_TEXT, PLAYER_P_TEXT, main_01_TEXT g_SHARED group SHARED, SHARED_ main_03 group SCROLLY3_TEXT, MOTION_3_TEXT, main_031_TEXT, main_032_TEXT, main_033_TEXT, main_034_TEXT, main_035_TEXT, main_036_TEXT @@ -3994,7 +3994,7 @@ loc_F04B: mov al, [bp+arg_0] mov ah, 0 push ax - call sub_F36B + call @dialog_face_load_unput_put_free_$qiii jmp loc_F0ED ; --------------------------------------------------------------------------- @@ -4316,108 +4316,13 @@ loc_F333: sub_F2B4 endp main__TEXT ends +DIALOG_TEXT segment byte public 'CODE' use16 + @DIALOG_FACE_LOAD_UNPUT_PUT_FREE_$QIII procdesc pascal near \ + left:word, top:word, cel:word +DIALOG_TEXT ends + main_0_TEXT segment byte public 'CODE' use16 -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_F36B proc near - -var_6 = word ptr -6 -var_4 = dword ptr -4 -arg_0 = word ptr 4 -@@top = word ptr 6 -@@left = word ptr 8 - - enter 6, 0 - push si - push di - mov di, offset aBss0_cd2_0 - mov [bp+var_6], offset aKao0_cd2_0 - cmp [bp+arg_0], (-1 and 255) - jz loc_F432 - cmp _Ems, 0 - jz loc_F40F - cmp _dialog_side, DIALOG_SIDE_PLAYCHAR - jnz short loc_F39C - mov [bp+var_4], 100000 - jmp short loc_F3A4 -; --------------------------------------------------------------------------- - -loc_F39C: - mov [bp+var_4], 200000 - -loc_F3A4: - mov si, _cdg_slots.CDG_plane_size + (size cdg_t * 2) - mov ax, [bp+arg_0] - imul si - imul ax, 5 - movzx eax, ax - add [bp+var_4], eax - push si - call hmem_allocbyte - mov _cdg_slots.seg_alpha + (size cdg_t * 2), ax - push _Ems - pushd [bp+var_4] - push ax - push 0 - movzx eax, si - push eax - call ems_read - movzx eax, si - add [bp+var_4], eax - mov ax, 4 - imul si - mov si, ax - push si - call hmem_allocbyte - mov _cdg_slots.seg_colors + (size cdg_t * 2), ax - push _Ems - pushd [bp+var_4] - push ax - push 0 - movzx eax, si - push eax - call ems_read - movzx eax, si - add [bp+var_4], eax - jmp short loc_F432 -; --------------------------------------------------------------------------- - -loc_F40F: - cmp _dialog_side, DIALOG_SIDE_PLAYCHAR - jz short loc_F41B - mov al, _stage_id - jmp short loc_F421 -; --------------------------------------------------------------------------- - -loc_F41B: - mov di, [bp+var_6] - mov al, _playchar - -loc_F421: - add al, 30h ; '0' - mov [di+3], al - call cdg_load_single pascal, CDG_FACESET_PLAYCHAR, ds, di, [bp+arg_0] - -loc_F432: - push 1 - call frame_delay - call @dialog_face_unput_8$quiui pascal, [bp+@@left], [bp+@@top] - cmp [bp+arg_0], (-1 and 255) - jz short loc_F45D - call cdg_put_8 pascal, [bp+@@left], [bp+@@top], CDG_FACESET_PLAYCHAR - call cdg_free pascal, CDG_FACESET_PLAYCHAR - -loc_F45D: - pop di - pop si - leave - retn 6 -sub_F36B endp - - ; =============== S U B R O U T I N E ======================================= ; Attributes: bp-based frame @@ -24929,8 +24834,9 @@ aSt06b db 'st06b',0 aDemo5_rec db 'DEMO5.REC',0 ; char aOp_0[] aOp_0 db 'op',0 -aBss0_cd2_0 db 'BsS0.cD2',0 -aKao0_cd2_0 db 'KaO0.cD2',0 +public _faceset_boss_format, _faceset_playchar_format +_faceset_boss_format db 'BsS0.cD2',0 +_faceset_playchar_format db 'KaO0.cD2',0 aBb0_cdg db 'bb0.cdg',0 aBb1_cdg db 'bb1.cdg',0 aBb2_cdg db 'bb2.cdg',0