[Decompilation] [th02] Dialog: Face rendering

Part of P0260, funded by Yanga.
This commit is contained in:
nmlgc 2023-10-26 11:37:38 +02:00
parent be31caeba8
commit c4622992b5
5 changed files with 152 additions and 106 deletions

View File

@ -6,7 +6,11 @@ typedef Planar<mpn_plane_t> mpn_image_t;
typedef struct {
char magic[4]; // = "MPTN"
uint8_t count; // Stored minus 1.
// Stored minus 1. (Probably because MIKO_K.MPN contains 256 tiles and ZUN
// absolutely wanted to store this value in a single byte regardless.)
uint8_t count;
int8_t unused;
} mpn_header_t;

View File

@ -2,6 +2,7 @@
#include "platform.h"
#include "x86real.h"
#include "pc98.h"
#include "planar.h"
#include "shiftjis.hpp"
#include "master.hpp"
extern "C" {
@ -9,6 +10,8 @@ extern "C" {
}
#include "th02/hardware/pages.hpp"
#include "th02/formats/dialog.hpp"
#include "th02/formats/tile.hpp"
#include "th02/formats/mpn.hpp"
#include "th02/main/playfld.hpp"
#include "th02/main/score.hpp"
#include "th02/main/scroll.hpp"
@ -18,6 +21,7 @@ extern "C" {
#include "th02/main/player/player.hpp"
#include "th02/main/tile/tile.hpp"
#include "th02/sprites/main_pat.h"
#include "th02/sprites/face.hpp"
// Coordinates
// -----------
@ -36,6 +40,9 @@ static const pixel_t BOX_MIDDLE_W = (
);
static const pixel_t BOX_SLIDE_SPEED = (PLAYFIELD_W / 24);
static const screen_x_t FACE_LEFT = (BOX_LEFT + 8);
static const screen_y_t FACE_TOP = (BOX_TOP + 8);
// -----------
// State
@ -267,3 +274,38 @@ void near dialog_post(void)
graph_accesspage(page_back);
}
void pascal near dialog_face_put(
int topleft_id // ACTUAL TYPE: face_topleft_id_t
)
{
static_assert(FACE_TILES_X == 3);
static_assert(FACE_TILES_Y == 3);
vram_y_t top1;
vram_y_t top2 = 0;
vram_y_t top3 = 0;
top1 = scroll_screen_y_to_vram(top1, FACE_TOP);
scroll_add_scrolled(top2, top1, TILE_H);
scroll_add_scrolled(top3, top2, TILE_H);
if(topleft_id == FACE_COL_0) {
grcg_setcolor(GC_RMW, 0);
grcg_boxfill(
FACE_LEFT, top1, (FACE_LEFT + FACE_W - 1), (top1 + FACE_H - 1)
);
grcg_off();
return;
}
mpn_put_8((FACE_LEFT + (0 * TILE_W)), top1, face_tile_id(topleft_id, 0, 0));
mpn_put_8((FACE_LEFT + (1 * TILE_W)), top1, face_tile_id(topleft_id, 1, 0));
mpn_put_8((FACE_LEFT + (2 * TILE_W)), top1, face_tile_id(topleft_id, 2, 0));
mpn_put_8((FACE_LEFT + (0 * TILE_W)), top2, face_tile_id(topleft_id, 0, 1));
mpn_put_8((FACE_LEFT + (1 * TILE_W)), top2, face_tile_id(topleft_id, 1, 1));
mpn_put_8((FACE_LEFT + (2 * TILE_W)), top2, face_tile_id(topleft_id, 2, 1));
mpn_put_8((FACE_LEFT + (0 * TILE_W)), top3, face_tile_id(topleft_id, 0, 2));
mpn_put_8((FACE_LEFT + (1 * TILE_W)), top3, face_tile_id(topleft_id, 1, 2));
mpn_put_8((FACE_LEFT + (2 * TILE_W)), top3, face_tile_id(topleft_id, 2, 2));
}

71
th02/sprites/face.hpp Normal file
View File

@ -0,0 +1,71 @@
// TH02 stores its 48×48 faces for in-game dialogs as 3×3 sets of .MPN tiles in
// MIKO_K.PTN… yup.
#define FACE_TILES_X (FACE_W / TILE_W)
#define FACE_TILES_Y (FACE_H / TILE_H)
#define FACE_TILE_STRIDE 16
// The 20 faces are arranged by placing a 5×4 grid of 3×3 tiles on the left
// side of a 16×12 grid. This results in the inner (face_col, face_row) values
// for the outer .MPN tile IDs:
//
// 012 345 678 9AB CDE F
// ┌───────────────────┐
// 0 │0 |1 |2 |3 |4 |
// 1 │ , | , | , | , | , |
// 2 │ 0| 0| 0| 0| 0|
// ├───────────────────┤
// 3 │0 |1 |2 |3 |4 |
// 4 │ , | , | , | , | , |
// 5 │ 1| 1| 1| 1| 1|
// ├───────────────────┤
// 6 │0 |1 |2 |3 |4 |
// 7 │ , | , | , | , | , |
// 8 │ 2| 2| 2| 2| 2|
// ├───────────────────┤
// 9 │0 |1 |2 |3 |4 |
// A │ , | , | , | , | , |
// B │ 3| 3| 3| 3| 3|
// └───────────────────┘
#define topleft_id_at(face_col, face_row) ( \
(face_row * FACE_TILES_Y * FACE_TILE_STRIDE) + (face_col * FACE_TILES_X) \
)
// Only stores the top-left ID for every face; the remaining ones can be
// calculated from the tile layout.
typedef enum face_tile_topleft_t {
FACE_REIMU_NEUTRAL = topleft_id_at(0, 0),
FACE_REIMU_HUSHED = topleft_id_at(1, 0),
FACE_REIMU_ANGRY = topleft_id_at(2, 0),
FACE_REIMU_JOY = topleft_id_at(3, 0),
FACE_REIMU_FROWN = topleft_id_at(4, 0),
FACE_REIMU_FALL = topleft_id_at(0, 1),
FACE_REIMU_CRY = topleft_id_at(1, 1),
FACE_REIMU_QUESTION = topleft_id_at(2, 1),
FACE_REIMU_SWEAT = topleft_id_at(3, 1),
FACE_REIMU_FLIRTY = topleft_id_at(4, 1), // Best guess given its usage... :/
FACE_GENJII = topleft_id_at(0, 2),
FACE_RIKA = topleft_id_at(1, 2),
FACE_MEIRA_NEUTRAL = topleft_id_at(2, 2),
FACE_MIMA_SMILE = topleft_id_at(3, 2),
FACE_MIMA_FROWN = topleft_id_at(4, 2),
FACE_MARISA_SMILE = topleft_id_at(0, 3),
FACE_MARISA_FROWN = topleft_id_at(1, 3),
FACE_MEIRA_SWEAT = topleft_id_at(2, 3),
FACE_EXRIKA_SMILE = topleft_id_at(3, 3),
FACE_EXRIKA_FROWN = topleft_id_at(4, 3),
// Fills the face area with hardware color 0 and doesn't blit any tile.
FACE_COL_0 = 0xFF,
};
#undef topleft_id_at
inline int face_tile_id(
int topleft, // ACTUAL TYPE: face_tile_topleft_t
int inner_col,
int inner_row
) {
return (topleft + (inner_row * FACE_TILE_STRIDE) + inner_col);
}

View File

@ -3,10 +3,17 @@
/// Sprite sizes
/// ------------
#define FACE_W 48
#define FACE_H 48
#define DIALOG_BOX_PART_W 32
#define DIALOG_BOX_PART_H 32
#define DIALOG_BOX_LEFT_W 96
#define DIALOG_BOX_FACE_BORDER 8
#define DIALOG_BOX_LEFT_W ( \
(DIALOG_BOX_FACE_BORDER * 2) + FACE_W + DIALOG_BOX_PART_W \
)
#define DIALOG_BOX_LEFT_PARTS (DIALOG_BOX_LEFT_W / DIALOG_BOX_PART_W)
/// ------------

View File

@ -43,6 +43,28 @@ DIALOG_LINE_LENGTH = 36
DIALOG_LINE_SIZE = (DIALOG_LINE_LENGTH + 4)
DIALOG_BOX_LINES = 2
FACE_REIMU_NEUTRAL = 0
FACE_REIMU_HUSHED = 3
FACE_REIMU_ANGRY = 6
FACE_REIMU_JOY = 9
FACE_REIMU_FROWN = 12
FACE_REIMU_FALL = 48
FACE_REIMU_CRY = 51
FACE_REIMU_QUESTION = 54
FACE_REIMU_SWEAT = 57
FACE_REIMU_FLIRTY = 60
FACE_GENJII = 96
FACE_RIKA = 99
FACE_MEIRA_NEUTRAL = 102
FACE_MIMA_SMILE = 105
FACE_MIMA_FROWN = 108
FACE_MARISA_SMILE = 144
FACE_MARISA_FROWN = 147
FACE_MEIRA_SWEAT = 150
FACE_EXRIKA_SMILE = 153
FACE_EXRIKA_FROWN = 156
FACE_COL_0 = 255
main_01 group main_01_TEXT, POINTNUM_TEXT, main_01__TEXT, ITEM_TEXT, HUD_TEXT, main_01___TEXT, PLAYER_B_TEXT, main_01____TEXT
main_03 group main_03_TEXT, DIALOG_TEXT, main_03__TEXT
@ -12370,112 +12392,12 @@ sub_12B9E endp
extern @dialog_load_and_init$qv:proc
@dialog_pre$qv procdesc near
@dialog_post$qv procdesc near
@DIALOG_FACE_PUT$QI procdesc pascal near \
topleft_id:word
DIALOG_TEXT ends
main_03__TEXT segment byte public 'CODE' use16
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
sub_12F23 proc near
@@top_2 = word ptr -4
@@top_1 = word ptr -2
@@mpn_image = word ptr 4
enter 4, 0
push si
push di
mov di, [bp+@@mpn_image]
mov [bp+@@top_1], 0
mov [bp+@@top_2], 0
mov si, 328
add si, _scroll_line
cmp si, RES_Y
jl short loc_12F47
sub si, RES_Y
loc_12F47:
lea ax, [si+TILE_H]
add [bp+@@top_1], ax
cmp [bp+@@top_1], RES_Y
jl short loc_12F59
sub [bp+@@top_1], RES_Y
loc_12F59:
mov ax, [bp+@@top_1]
add ax, TILE_H
add [bp+@@top_2], ax
cmp [bp+@@top_2], RES_Y
jl short loc_12F6E
sub [bp+@@top_2], RES_Y
loc_12F6E:
cmp di, 255
jnz short loc_12F94
call grcg_setcolor pascal, (GC_RMW shl 16) + 0
push 40
push si
push 87
lea ax, [si+47]
push ax
call grcg_boxfill
call grcg_off
jmp short loc_13009
; ---------------------------------------------------------------------------
loc_12F94:
call @mpn_put_8$qiii pascal, 40, si, di
push 56 ; left
push si ; top
lea ax, [di+1]
push ax ; image
call @mpn_put_8$qiii
push 72 ; left
push si ; top
lea ax, [di+2]
push ax ; image
call @mpn_put_8$qiii
push 40 ; left
push [bp+@@top_1] ; top
lea ax, [di+10h]
push ax ; image
call @mpn_put_8$qiii
push 56 ; left
push [bp+@@top_1] ; top
lea ax, [di+11h]
push ax ; image
call @mpn_put_8$qiii
push 72 ; left
push [bp+@@top_1] ; top
lea ax, [di+12h]
push ax ; image
call @mpn_put_8$qiii
push 40 ; left
push [bp+@@top_2] ; top
lea ax, [di+20h]
push ax ; image
call @mpn_put_8$qiii
push 56 ; left
push [bp+@@top_2] ; top
lea ax, [di+21h]
push ax ; image
call @mpn_put_8$qiii
push 72 ; left
push [bp+@@top_2] ; top
lea ax, [di+22h]
push ax ; image
call @mpn_put_8$qiii
loc_13009:
pop di
pop si
leave
retn 2
sub_12F23 endp
; =============== S U B R O U T I N E =======================================
; Attributes: bp-based frame
@ -12534,7 +12456,7 @@ sub_13055 proc near
var_4 = word ptr -4
var_2 = word ptr -2
@@mpn_image = word ptr 4
@@topleft_id = word ptr 4
enter 4, 0
push si
@ -12551,7 +12473,7 @@ var_2 = word ptr -2
loc_13090:
call _input_sense
call sub_12F23 pascal, [bp+@@mpn_image]
call @dialog_face_put$qi pascal, [bp+@@topleft_id]
cmp si, 24h ; '$'
jg short loc_130B3
push 0