mirror of https://github.com/nmlgc/ReC98.git
[Decompilation] [th03] .MRS: Alpha-tested byte-aligned blitting
And since inlining even removes longer if-else chains if they branch depending on a literal constant, we can use a regular parameter to select either MOV or OR in our _FS and _GS poke() template functions, without needing to duplicate them! Part of P0127, funded by [Anonymous].
This commit is contained in:
parent
8b0165738a
commit
00e65f4c6b
23
decomp.h
23
decomp.h
|
@ -57,6 +57,7 @@
|
|||
// types.
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
struct Decomp_ES { void __seg* value() { return (void __seg *)(_ES); } };
|
||||
struct Decomp_FS { void __seg* value() { return (void __seg *)(_FS); } };
|
||||
struct Decomp_GS { void __seg* value() { return (void __seg *)(_GS); } };
|
||||
struct Decomp_DI { void __near* value() { return (void __near *)(_DI); } };
|
||||
|
@ -65,20 +66,28 @@
|
|||
// perfects the inlining.
|
||||
#define poked(sgm, off, val) \
|
||||
_EAX = val; \
|
||||
poked_eax((Decomp##sgm *)NULL, (Decomp##off *)NULL);
|
||||
poked_eax((Decomp##sgm *)NULL, (Decomp##off *)NULL, (uint8_t)(0x89));
|
||||
|
||||
#define poke_or_d(sgm, off, val) \
|
||||
_EAX = val; \
|
||||
poked_eax((Decomp##sgm *)NULL, (Decomp##off *)NULL, (uint8_t)(0x09));
|
||||
|
||||
template <class Segment, class Offset> inline void poked_eax(
|
||||
Segment *sgm, Offset *off
|
||||
Segment *sgm, Offset *off, uint8_t op
|
||||
) {
|
||||
*reinterpret_cast<uint32_t far *>(sgm->value() + off->value()) = _EAX;
|
||||
if(op == 0x89) {
|
||||
*(uint32_t far *)(sgm->value() + off->value()) = _EAX;
|
||||
} else if(op == 0x09) {
|
||||
*(uint32_t far *)(sgm->value() + off->value()) |= _EAX;
|
||||
}
|
||||
}
|
||||
|
||||
inline void poked_eax(Decomp_FS *sgm, Decomp_DI *off) {
|
||||
__emit__(0x66, 0x64, 0x89, 0x05); // MOV FS:[DI], EAX
|
||||
inline void poked_eax(Decomp_FS *sgm, Decomp_DI *off, uint8_t op) {
|
||||
__emit__(0x66, 0x64, op, 0x05); // [op] FS:[DI], EAX
|
||||
}
|
||||
|
||||
inline void poked_eax(Decomp_GS *sgm, Decomp_DI *off) {
|
||||
__emit__(0x66, 0x65, 0x89, 0x05); // MOV GS:[DI], EAX
|
||||
inline void poked_eax(Decomp_GS *sgm, Decomp_DI *off, uint8_t op) {
|
||||
__emit__(0x66, 0x65, op, 0x05); // [op] GS:[DI], EAX
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
#pragma option -3
|
||||
#pragma option -3 -Z-
|
||||
#pragma codeseg SHARED
|
||||
|
||||
extern "C" {
|
||||
#include <dos.h>
|
||||
#include <stddef.h>
|
||||
#include "platform.h"
|
||||
#include "pc98.h"
|
||||
#include "planar.h"
|
||||
#include "decomp.h"
|
||||
#include "master.hpp"
|
||||
#include "th03/formats/hfliplut.h"
|
||||
}
|
||||
|
||||
#include "th03/formats/mrs.hpp"
|
||||
|
||||
#undef grcg_off
|
||||
#define grcg_off() { \
|
||||
_AL ^= _AL; \
|
||||
__asm out 0x7C, al; \
|
||||
}
|
||||
|
||||
static const vram_byte_amount_t MRS_BYTE_W = (MRS_W / BYTE_DOTS);
|
||||
static const vram_dword_amount_t MRS_DWORD_W = (MRS_BYTE_W / sizeof(dots32_t));
|
||||
|
||||
|
@ -67,6 +75,15 @@ struct mrs_at_G_t : public mrs_plane_t {
|
|||
static inline mrs_at_G_t near* mrs_at_G(void) {
|
||||
return reinterpret_cast<mrs_at_G_t near *>(offsetof(mrs_t, planes.G));
|
||||
}
|
||||
|
||||
// At least mrs_put_8() is somewhat sane.
|
||||
struct mrs_at_B_t : public mrs_plane_t {
|
||||
dots32_t dots_from_alpha(void) const { return *(*((this + 0)->dots)); }
|
||||
dots32_t dots_from_B(void) const { return *(*((this + 1)->dots)); }
|
||||
dots32_t dots_from_R(void) const { return *(*((this + 2)->dots)); }
|
||||
dots32_t dots_from_G(void) const { return *(*((this + 3)->dots)); }
|
||||
dots32_t dots_from_E(void) const { return *(*((this + 4)->dots)); }
|
||||
};
|
||||
// -------------------------
|
||||
|
||||
inline uint16_t to_bottom_left_8(const screen_x_t &left) {
|
||||
|
@ -79,6 +96,57 @@ inline seg_t to_segment(const uscreen_y_t &top) {
|
|||
return ((_AX << 2) + _DX); // ... and -> segment
|
||||
}
|
||||
|
||||
void pascal mrs_put_8(screen_x_t left, uscreen_y_t top, int slot)
|
||||
{
|
||||
#define _SI reinterpret_cast<mrs_at_B_t near *>(_SI)
|
||||
|
||||
grcg_setcolor(GC_RMW, 0);
|
||||
_DI = to_bottom_left_8(left);
|
||||
_AX = to_segment(top);
|
||||
|
||||
// "I've spent good money on that Intel 386 CPU, so let's actually use
|
||||
// *all* its segment registers!" :zunpet: :zunpet: :zunpet:
|
||||
_ES = (_AX += SEG_PLANE_B); // = B
|
||||
_FS = (_AX += SEG_PLANE_DIST_BRG); // = R
|
||||
_GS = (_AX += SEG_PLANE_DIST_BRG); // = G
|
||||
|
||||
__asm { push ds; }
|
||||
mrs_slot_assign(ds, si, slot);
|
||||
|
||||
_DX = MRS_DWORD_W;
|
||||
__asm { nop; }
|
||||
mrs_put_rows(_DX, REP MOVSD);
|
||||
grcg_off();
|
||||
|
||||
// Reset to bottom left
|
||||
_SI = 0;
|
||||
_DI += (MRS_H * ROW_SIZE);
|
||||
|
||||
_BX = (_GS + SEG_PLANE_DIST_E); // = E
|
||||
_DX = MRS_DWORD_W;
|
||||
mrs_put_rows(_DX, { put:
|
||||
_EAX = _SI->dots_from_alpha();
|
||||
_EAX |= _EAX;
|
||||
if(!FLAGS_ZERO) {
|
||||
poke_or_d(_ES, _DI, _SI->dots_from_B());
|
||||
poke_or_d(_FS, _DI, _SI->dots_from_R());
|
||||
poke_or_d(_GS, _DI, _SI->dots_from_G());
|
||||
_GS = _BX;
|
||||
poke_or_d(_GS, _DI, _SI->dots_from_E());
|
||||
_GS = (_BX - SEG_PLANE_DIST_E);
|
||||
}
|
||||
reinterpret_cast<uint16_t>(_SI) += sizeof(dots32_t);
|
||||
_DI += sizeof(dots32_t);
|
||||
__asm { loop put; }
|
||||
});
|
||||
|
||||
__asm { pop ds; }
|
||||
|
||||
#undef _SI
|
||||
}
|
||||
|
||||
#pragma codestring "\x90"
|
||||
|
||||
void pascal mrs_put_noalpha_8(
|
||||
screen_x_t left, uscreen_y_t top, int slot, bool altered_colors
|
||||
)
|
||||
|
@ -92,8 +160,6 @@ void pascal mrs_put_noalpha_8(
|
|||
mrs_slot_assign(ds, si, slot);
|
||||
_SI = mrs_at_G();
|
||||
|
||||
// "I've spent good money on that Intel 386 CPU, so let's actually use
|
||||
// *all* its segment registers!" :zunpet: :zunpet: :zunpet:
|
||||
_FS = (_AX += SEG_PLANE_B); // = B
|
||||
_GS = (_AX += SEG_PLANE_DIST_BRG); // = R
|
||||
_ES = (_AX += SEG_PLANE_DIST_BRG); // = G
|
||||
|
|
|
@ -7,6 +7,9 @@ static const int MRS_SLOT_COUNT = 8;
|
|||
static const pixel_t MRS_W = 288;
|
||||
static const pixel_t MRS_H = 184;
|
||||
|
||||
// Displays the .MRS image in the given [slot] at (⌊left/8⌋*8, top).
|
||||
void pascal mrs_put_8(screen_x_t left, uscreen_y_t top, int slot);
|
||||
|
||||
// Displays the .MRS image in the given [slot] at (⌊left/8⌋*8, top),
|
||||
// disregarding its alpha plane, and optionally altering its colors slightly.
|
||||
void pascal mrs_put_noalpha_8(
|
||||
|
|
112
th03_main.asm
112
th03_main.asm
|
@ -5152,29 +5152,29 @@ sub_C8C4 endp
|
|||
|
||||
sub_C9FE proc far
|
||||
|
||||
arg_0 = byte ptr 6
|
||||
@@mrs_slot = byte ptr 6
|
||||
|
||||
push bp
|
||||
mov bp, sp
|
||||
push si
|
||||
mov al, [bp+arg_0]
|
||||
mov al, [bp+@@mrs_slot]
|
||||
mov ah, 0
|
||||
mov bx, ax
|
||||
cmp byte ptr [bx+798h], 1
|
||||
jnz short loc_CA37
|
||||
mov si, 10h
|
||||
cmp [bp+arg_0], 0
|
||||
mov si, PLAYFIELD_LEFT
|
||||
cmp [bp+@@mrs_slot], 0
|
||||
jz short loc_CA1D
|
||||
add si, 140h
|
||||
add si, PLAYFIELD_W_BORDERED
|
||||
|
||||
loc_CA1D:
|
||||
push si
|
||||
push 10h
|
||||
mov al, [bp+arg_0]
|
||||
push si ; left
|
||||
push PLAYFIELD_TOP ; top
|
||||
mov al, [bp+@@mrs_slot]
|
||||
mov ah, 0
|
||||
push ax
|
||||
call sub_EF46
|
||||
mov al, [bp+arg_0]
|
||||
push ax ; slot
|
||||
call @mrs_put_8$qiuii
|
||||
mov al, [bp+@@mrs_slot]
|
||||
mov ah, 0
|
||||
mov bx, ax
|
||||
mov byte ptr [bx+798h], 2
|
||||
|
@ -8963,95 +8963,7 @@ sub_EF1C endp
|
|||
|
||||
; ---------------------------------------------------------------------------
|
||||
nop
|
||||
|
||||
; =============== S U B R O U T I N E =======================================
|
||||
|
||||
; Attributes: bp-based frame
|
||||
|
||||
sub_EF46 proc far
|
||||
|
||||
arg_0 = word ptr 6
|
||||
arg_2 = word ptr 8
|
||||
arg_4 = word ptr 0Ah
|
||||
|
||||
push bp
|
||||
mov bp, sp
|
||||
push si
|
||||
push di
|
||||
call grcg_setcolor pascal, GC_RMW, 0
|
||||
mov ax, [bp+arg_4]
|
||||
sar ax, 3
|
||||
add ax, 3930h
|
||||
mov di, ax
|
||||
mov ax, [bp+arg_2]
|
||||
shr ax, 1
|
||||
mov dx, ax
|
||||
shl ax, 2
|
||||
add ax, dx
|
||||
add ax, 0A800h
|
||||
mov es, ax
|
||||
assume es:nothing
|
||||
add ax, 800h
|
||||
mov fs, ax
|
||||
add ax, 800h
|
||||
mov gs, ax
|
||||
push ds
|
||||
mov bx, [bp+arg_0]
|
||||
shl bx, 2
|
||||
lds si, _mrs_images[bx]
|
||||
mov dx, 9
|
||||
nop
|
||||
|
||||
loc_EF8A:
|
||||
mov cx, dx
|
||||
rep movsd
|
||||
sub di, 74h ; 't'
|
||||
jnb short loc_EF8A
|
||||
GRCG_OFF_VIA_XOR al
|
||||
xor si, si
|
||||
add di, 3980h
|
||||
mov ax, gs
|
||||
add ax, 2800h
|
||||
mov bx, ax
|
||||
mov dx, 9
|
||||
|
||||
loc_EFA8:
|
||||
mov cx, dx
|
||||
|
||||
loc_EFAA:
|
||||
mov eax, [si]
|
||||
or eax, eax
|
||||
jz short loc_EFDF
|
||||
mov eax, [si+19E0h]
|
||||
or es:[di], eax
|
||||
mov eax, [si+33C0h]
|
||||
or fs:[di], eax
|
||||
mov eax, [si+4DA0h]
|
||||
or gs:[di], eax
|
||||
mov gs, bx
|
||||
assume gs:nothing
|
||||
mov eax, [si+6780h]
|
||||
or gs:[di], eax
|
||||
mov ax, bx
|
||||
sub ax, 2800h
|
||||
mov gs, ax
|
||||
assume gs:nothing
|
||||
|
||||
loc_EFDF:
|
||||
add si, 4
|
||||
add di, 4
|
||||
loop loc_EFAA
|
||||
sub di, 74h ; 't'
|
||||
jnb short loc_EFA8
|
||||
pop ds
|
||||
pop di
|
||||
pop si
|
||||
pop bp
|
||||
retf 6
|
||||
sub_EF46 endp
|
||||
|
||||
; ---------------------------------------------------------------------------
|
||||
nop
|
||||
extern @MRS_PUT_8$QIUII:proc
|
||||
extern @MRS_PUT_NOALPHA_8$QIUIIC:proc
|
||||
extern @MRS_HFLIP$QI:proc
|
||||
SPRITE16_SPRITES_COMMIT procdesc pascal far
|
||||
|
|
Loading…
Reference in New Issue