[Decompilation] [th01] .GRZ file loading and display

Yet another run-length encoded graphics format, this one being
exclusively used to wastefully store Konngara's sword slash and kuji-in
kill "animation".

But for once, the terrible code generated by inline functions with
non-literal parameters perfectly matches what ZUN wrote here.

Part of P0081, funded by Ember2528.
This commit is contained in:
nmlgc 2020-03-03 19:41:02 +01:00
parent 54e5bf39fc
commit fd6a8bae81
10 changed files with 377 additions and 2314 deletions

View File

@ -41,12 +41,12 @@ th05:: $(TH05:\=bin\th05\)
bin\th01\zunsoft.com: th01\zunsoft.c
$(CC) $(CFLAGS) -mt -lt -nbin\th01\ $** masters.lib
bin\th01\op.exe: bin\th01\op.obj th01\op_02.c th01\op_03.c th01\op_04.c th01\op_05.c th01\op_06.cpp th01\op_08.c th01\op_10.c th01\op_11.c th01\op_12.cpp
bin\th01\op.exe: bin\th01\op.obj th01\op_02.c th01\op_03.c th01\op_04.c th01\op_05.c th01\op_06.cpp th01\op_08.c th01\op_09.cpp th01\op_10.c th01\op_11.c th01\op_12.cpp
$(CC) $(CFLAGS) -ml -3 -DGAME=1 -nbin\th01\ -eOP.EXE @&&|
$**
|
bin\th01\reiiden.exe: bin\th01\reiiden.obj th01\main_02.c th01\main_03.c th01\main_04.c th01\main_05.c th01\main_06.cpp th01\main_12.c th01\main_13.c th01\main_14.c th01\main_16.c
bin\th01\reiiden.exe: bin\th01\reiiden.obj th01\main_02.c th01\main_03.c th01\main_04.c th01\main_05.c th01\main_06.cpp th01\main_08.cpp th01\main_12.c th01\main_13.c th01\main_14.c th01\main_16.c
$(CC) $(CFLAGS) -ml -3 -DGAME=1 -nbin\th01\ -eREIIDEN.EXE @&&|
$**
|

245
th01/formats/grz.cpp Normal file
View File

@ -0,0 +1,245 @@
#pragma option -Z
extern "C" {
#include <stddef.h>
#include <string.h>
#include <master.h>
#include "ReC98.h"
#include "th01/hardware/graph.h"
#include "th01/formats/grz.h"
extern const char HGRZ_MAGIC[4];
extern const char HGRX_MAGIC[4];
extern char planar_stream_id;
extern char grx_col;
extern uint8_t* rle_streams[GRX_COUNT];
// Actually a planar8_t*, but used like a dots8_t* everywhere.
extern dots8_t* planar_streams[GRX_COUNT][PLANAR_STREAM_PER_GRX_COUNT];
extern unsigned char planar_stream_count[GRX_COUNT];
struct grz_header_t {
char magic[sizeof(HGRZ_MAGIC)];
uint8_t image_count;
int8_t padding[3];
int32_t offsets[GRZ_IMAGE_COUNT];
int32_t total_size; // including this header
int8_t unknown[20];
};
struct grx_header_t {
char magic[sizeof(HGRX_MAGIC)];
uint8_t planar_stream_count;
int8_t unused_1[3];
uint16_t rle_stream_size;
uint16_t planar_stream_size;
int8_t unused_2[52];
};
void grx_put_stream(unsigned int slot, int planar_stream)
{
if(planar_stream_count[slot] > planar_stream) {
planar_stream_id = planar_stream;
grx_put(slot);
planar_stream_id = 0;
}
}
void grx_put_col(unsigned int slot, uint4_t col)
{
grx_col = (col + 1);
grx_put(slot);
grx_col = 0;
}
inline void vram_put(seg_t segment, uint16_t offset, dots8_t dots)
{
*reinterpret_cast<dots8_t far *>(MK_FP(segment, offset)) = dots;
}
void grx_put(unsigned int slot)
{
uint8_t command;
uint8_t runs;
uint8_t *rle = rle_streams[slot];
dots8_t *planar = planar_streams[slot][planar_stream_id];
#define put(vram_offset, vram_offset_last, planar) \
if(!grx_col) { \
vram_put(SEG_PLANE_B, vram_offset, *(planar++)); \
vram_put(SEG_PLANE_R, vram_offset, *(planar++)); \
vram_put(SEG_PLANE_G, vram_offset, *(planar++)); \
vram_put(SEG_PLANE_E, vram_offset_last, *(planar++)); \
} else { \
vram_put(SEG_PLANE_B, vram_offset_last, 0xFF); \
}
if(grx_col) {
grcg_setcolor_rmw(grx_col - 1);
}
for(uint16_t vram_offset = 0; vram_offset < PLANE_SIZE; vram_offset++) {
command = *(rle++);
if(command == GC_RUN) {
runs = *(rle++);
if(runs) {
command = *(rle++);
while(runs--) {
if(command == GC_PUT) {
put(vram_offset, vram_offset++, planar);
} else {
vram_offset++;
}
}
}
}
// Yes, in case we just did a putting GC_RUN, we are in fact putting
// one more byte!
if(command == GC_PUT) {
put(vram_offset, vram_offset, planar);
}
}
if(grx_col) {
grcg_off();
}
#undef put
}
/// Loading and freeing
/// -------------------
#define fail_if(cond) \
if(cond) { \
file_close(); \
return 1; \
}
#define grx_header_read(grx, slot) \
file_read(&grx, sizeof(grx)); \
fail_if(memcmp(grx.magic, HGRX_MAGIC, sizeof(HGRX_MAGIC))); \
fail_if(grx.planar_stream_count < 1); \
planar_stream_count[slot] = grx.planar_stream_count; \
#define rle_stream_new(slot, size) \
if(rle_streams[slot]) { \
grx_free(slot); \
} \
fail_if((rle_streams[slot] = new uint8_t[size]) == NULL);
#define rle_stream_read(slot, size) \
file_read(rle_streams[slot], size);
#define planar_streams_new(slot, stream_count, size) \
for(i = 0; i < stream_count; i++) { \
if(planar_streams[slot][i]) { \
grx_free(slot); \
} \
fail_if((planar_streams[slot][i] = new uint8_t[size]) == NULL); \
}
#define planar_streams_read(slot, stream_count, size) \
for(i = 0; i < stream_count; i++) { \
file_read(planar_streams[slot][i], size); \
}
union headers_t {
grz_header_t grz;
grx_header_t grx;
int8_t space[100];
};
int grx_load(unsigned int slot, const char *fn)
{
uint16_t rle_size;
uint16_t planar_size;
if(!file_ropen(fn)) {
return 1;
}
headers_t* h = new headers_t[1];
grx_header_read(h->grx, slot);
rle_size = h->grx.rle_stream_size;
planar_size = h->grx.planar_stream_size;
int i;
rle_stream_new(slot, rle_size);
planar_streams_new(slot, h->grx.planar_stream_count, planar_size);
rle_stream_read(slot, rle_size);
planar_streams_read(slot, h->grx.planar_stream_count, planar_size);
delete[] h;
file_close();
return 0;
}
int grx_load_noplanar(unsigned int slot, const char *fn)
{
uint16_t rle_size;
if(!file_ropen(fn)) {
return 1;
}
headers_t* h = new headers_t[1];
grx_header_read(h->grx, slot);
rle_size = h->grx.rle_stream_size;
rle_stream_new(slot, rle_size);
rle_stream_read(slot, rle_size);
delete[] h;
file_close();
return 0;
}
void grx_free(unsigned int slot)
{
if(rle_streams[slot]) {
delete[] rle_streams[slot];
rle_streams[slot] = NULL;
}
for(int i = 0; i < PLANAR_STREAM_PER_GRX_COUNT; i++) {
if(planar_streams[slot][i]) {
delete[] planar_streams[slot][i];
planar_streams[slot][i] = NULL;
}
}
}
int grz_load_single(unsigned int slot, const char *fn, int n)
{
register int i;
uint16_t rle_size;
uint16_t planar_size;
if(!file_ropen(fn)) {
return 1;
}
headers_t* h = new headers_t[1];
file_read(&h->grz, sizeof(h->grz));
fail_if(memcmp(h->grz.magic, HGRZ_MAGIC, sizeof(HGRZ_MAGIC)));
uint8_t image_count = h->grz.image_count;
if(image_count > n) {
// TODO: Srsly?
i = (offsetof(grz_header_t, offsets) + (n * sizeof(int32_t)));
int32_t offset = *reinterpret_cast<int32_t *>(&h->space[i]);
file_seek(offset, 0);
grx_header_read(h->grx, slot);
rle_size = h->grx.rle_stream_size;
planar_size = h->grx.planar_stream_size;
rle_stream_new(slot, rle_size);
planar_streams_new(slot, h->grx.planar_stream_count, planar_size);
rle_stream_read(slot, rle_size);
planar_streams_read(slot, h->grx.planar_stream_count, planar_size);
}
delete[] h;
file_close();
return 0;
}
/// -------------------
}

59
th01/formats/grz.h Normal file
View File

@ -0,0 +1,59 @@
/// Run-length encoded, 16-color + alpha, 640×400 image format
/// ----------------------------------------------------------
/// .GRX decouples the RLE command stream from the pixel data. This allows
/// either multiple pixel streams (stored as planar8_t) to be used with the
/// same RLE stream, or the RLE stream to be used on its own for a monochrome
/// byte-aligned pattern.
// RLE stream format
enum grx_rle_t {
// Puts the next byte from the pixel data source. No parameters.
GC_PUT = 0,
// Followed by:
// * a uint8_t with the length of this run in 8-dot units
// * a uint8_t with the command to use for all runs (0 = put, everything
// else = skip)
GC_RUN = 1,
};
// Static arrays
#define GRX_COUNT 16
#define PLANAR_STREAM_PER_GRX_COUNT 16
// File format limit
#define GRZ_IMAGE_COUNT 16
// Loading
// -------
// All of these load the file with the given [fn] into the given [slot],
// automatically freeing any previously loaded image in there, and return 0
// on success or 1 on failure.
// Loads the [n]th GRX image, with all of its planar streams, from a .GRZ
// file.
int grz_load_single(unsigned int slot, const char *fn, int n);
// Loads the given .GRX file, with all of its planar streams.
int grx_load(unsigned int slot, const char *fn);
// Loads only the RLE stream of the given .GRX file.
int grx_load_noplanar(unsigned int slot, const char *fn);
// -------
// Display
// -------
// Equivalent to grz_put_stream(slot, 0);
void grx_put(unsigned int slot);
// Displays the planar stream with the given number of the image loaded into
// the given GRX [slot].
void grx_put_stream(unsigned int slot, int planar_stream);
// Renders only the RLE stream in the given [col] via the GRCG, using a 0xFF
// pattern for every 8 dots to be displayed.
void grx_put_col(unsigned int slot, uint4_t col);
// -------
// Frees both the RLE and any BRGE8 streams in the given GRX [slot].
void grx_free(unsigned int slot);
/// ----------------------------------------------------------

View File

@ -0,0 +1,7 @@
GRX_COUNT = 16
PLANAR_STREAM_PER_GRX_COUNT = 16
public _rle_streams, _planar_streams, _planar_stream_count
_rle_streams dd GRX_COUNT dup (?)
_planar_streams dd GRX_COUNT dup (PLANAR_STREAM_PER_GRX_COUNT dup (?))
_planar_stream_count db GRX_COUNT dup (?)

View File

@ -0,0 +1,5 @@
public _planar_stream_id, _grx_col, _HGRX_MAGIC, _HGRZ_MAGIC
_planar_stream_id db 0
_grx_col db 0
_HGRX_MAGIC db 'HGRX',0
_HGRZ_MAGIC db 'HGRZ',0

6
th01/main_08.cpp Normal file
View File

@ -0,0 +1,6 @@
/* ReC98
* -----
* Code segment #8 of TH01's REIIDEN.EXE
*/
#include "th01/formats/grz.cpp"

6
th01/op_09.cpp Normal file
View File

@ -0,0 +1,6 @@
/* ReC98
* -----
* Code segment #9 of TH01's OP.EXE
*/
#include "th01/formats/grz.cpp"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -31549,42 +31549,14 @@ loc_2D06B:
loc_2D079:
push 0
call sub_11738
push 0
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
push 1
push ds
push offset aBoss8_grz ; "boss8.grz"
push 1
call sub_1117C
push 2
push ds
push offset aBoss8_grz ; "boss8.grz"
push 2
call sub_1117C
push 3
push ds
push offset aBoss8_grz ; "boss8.grz"
push 3
call sub_1117C
push 4
push ds
push offset aBoss8_grz ; "boss8.grz"
push 4
call sub_1117C
push 5
push ds
push offset aBoss8_grz ; "boss8.grz"
push 5
call sub_1117C
call _grz_load_single stdcall, 0, offset aBoss8_grz, ds, 0 ; "boss8.grz"
call _grz_load_single stdcall, 1, offset aBoss8_grz, ds, 1 ; "boss8.grz"
call _grz_load_single stdcall, 2, offset aBoss8_grz, ds, 2 ; "boss8.grz"
call _grz_load_single stdcall, 3, offset aBoss8_grz, ds, 3 ; "boss8.grz"
call _grz_load_single stdcall, 4, offset aBoss8_grz, ds, 4 ; "boss8.grz"
call _grz_load_single stdcall, 5, offset aBoss8_grz, ds, 5 ; "boss8.grz"
add sp, 32h
push 6
push ds
push offset aBoss8_grz ; "boss8.grz"
push 6
call sub_1117C
call _grz_load_single stdcall, 6, offset aBoss8_grz, ds, 6 ; "boss8.grz"
push 28h ; '('
call _frame_delay
add sp, 0Ah
@ -31777,8 +31749,7 @@ sub_2D241 proc far
; ---------------------------------------------------------------------------
loc_2D261:
push si
call sub_110ED
call _grx_free stdcall, si
pop cx
inc si
@ -31974,20 +31945,16 @@ sub_2D343 endp
sub_2D412 proc far
arg_0 = word ptr 6
@@slot = word ptr 6
push bp
mov bp, sp
push si
mov si, [bp+arg_0]
push 1
call _graph_accesspage_func
push si
call sub_10CDD
push 0
call _graph_accesspage_func
push si
call sub_10CDD
mov si, [bp+@@slot]
call _graph_accesspage_func stdcall, 1
call _grx_put stdcall, si
call _graph_accesspage_func stdcall, 0
call _grx_put stdcall, si
add sp, 8
pop si
pop bp
@ -33986,8 +33953,7 @@ sub_2E705 proc far
jl loc_2E7C2
cmp word_3A6CA, 32h ; '2'
jnz short loc_2E728
push 0
call sub_2D412
call sub_2D412 stdcall, 0
push 8
call _mdrv2_se_play
add sp, 4
@ -33997,8 +33963,7 @@ loc_2E728:
jl loc_2E7C2
cmp word_3A6CA, 3Ch ; '<'
jnz short loc_2E73F
push 1
call sub_2D412
call sub_2D412 stdcall, 1
pop cx
loc_2E73F:
@ -34006,8 +33971,7 @@ loc_2E73F:
jl short loc_2E7C2
cmp word_3A6CA, 64h ; 'd'
jnz short loc_2E754
push 2
call sub_2D412
call sub_2D412 stdcall, 2
pop cx
loc_2E754:
@ -34015,8 +33979,7 @@ loc_2E754:
jl short loc_2E7C2
cmp word_3A6CA, 78h ; 'x'
jnz short loc_2E769
push 3
call sub_2D412
call sub_2D412 stdcall, 3
pop cx
loc_2E769:
@ -34024,8 +33987,7 @@ loc_2E769:
jl short loc_2E7C2
cmp word_3A6CA, 8Ch
jnz short loc_2E780
push 4
call sub_2D412
call sub_2D412 stdcall, 4
pop cx
loc_2E780:
@ -34033,8 +33995,7 @@ loc_2E780:
jl short loc_2E7C2
cmp word_3A6CA, 0A0h ; '?'
jnz short loc_2E797
push 5
call sub_2D412
call sub_2D412 stdcall, 5
pop cx
loc_2E797:
@ -34042,8 +34003,7 @@ loc_2E797:
jl short loc_2E7C2
cmp word_3A6CA, 0AAh ; '?'
jnz short loc_2E7AE
push 6
call sub_2D412
call sub_2D412 stdcall, 6
pop cx
loc_2E7AE:
@ -35672,129 +35632,74 @@ loc_2F766:
call _z_graph_clear
call _mdrv2_bgm_stop
call _z_palette_set_show c, large (0 shl 16) or 0, large (0 shl 16) or 0
push 7
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
add sp, 8
push 0
call sub_10CDD
call _grz_load_single c, 0, offset aBoss8_grz, ds, 7 ; "boss8.grz"
call _grx_put stdcall, 0
pop cx
push 0Ah
call _frame_delay
pop cx
call _z_graph_clear
push 8
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
add sp, 8
call _grz_load_single c, 0, offset aBoss8_grz, ds, 8 ; "boss8.grz"
call _z_palette_set_show c, large (0Fh shl 16) or 00h, large (0Fh shl 16) or 0Fh
push 0
call sub_10CDD
call _grx_put stdcall, 0
pop cx
push 0Ah
call _frame_delay
pop cx
call _z_graph_clear
push 9
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
add sp, 8
call _grz_load_single c, 0, offset aBoss8_grz, ds, 9 ; "boss8.grz"
call _z_palette_set_show c, large (0 shl 16) or 0, large (0 shl 16) or 0
push 0
call sub_10CDD
call _grx_put stdcall, 0
pop cx
push 0Ah
call _frame_delay
pop cx
call _z_graph_clear
push 0Ah
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
add sp, 8
call _grz_load_single c, 0, offset aBoss8_grz, ds, 10 ; "boss8.grz"
call _z_palette_set_show c, large (0Fh shl 16) or 00h, large (0Fh shl 16) or 0Fh
push 0
call sub_10CDD
call _grx_put stdcall, 0
pop cx
push 0Ah
call _frame_delay
pop cx
call _z_graph_clear
push 0Bh
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
add sp, 8
call _grz_load_single c, 0, offset aBoss8_grz, ds, 11 ; "boss8.grz"
call _z_palette_set_show c, large (0 shl 16) or 0, large (0 shl 16) or 0
push 0
call sub_10CDD
call _grx_put stdcall, 0
pop cx
push 0Ah
call _frame_delay
pop cx
call _z_graph_clear
push 0Ch
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
add sp, 8
call _grz_load_single c, 0, offset aBoss8_grz, ds, 12 ; "boss8.grz"
call _z_palette_set_show c, large (0Fh shl 16) or 00h, large (0Fh shl 16) or 0Fh
push 0
call sub_10CDD
call _grx_put stdcall, 0
pop cx
push 0Ah
call _frame_delay
pop cx
call _z_graph_clear
push 0Dh
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
add sp, 8
call _grz_load_single c, 0, offset aBoss8_grz, ds, 13 ; "boss8.grz"
call _z_palette_set_show c, large (0 shl 16) or 0, large (0 shl 16) or 0
push 0
call sub_10CDD
call _grx_put stdcall, 0
pop cx
push 0Ah
call _frame_delay
pop cx
call _z_graph_clear
push 0Eh
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
add sp, 8
call _grz_load_single c, 0, offset aBoss8_grz, ds, 14 ; "boss8.grz"
call _z_palette_set_show c, large (0Fh shl 16) or 00h, large (0Fh shl 16) or 0Fh
push 0
call sub_10CDD
call _grx_put stdcall, 0
pop cx
push 0Ah
call _frame_delay
pop cx
call _z_graph_clear
push 0Fh
push ds
push offset aBoss8_grz ; "boss8.grz"
push 0
call sub_1117C
add sp, 8
call _grz_load_single c, 0, offset aBoss8_grz, ds, 15 ; "boss8.grz"
call _z_palette_set_show c, large (0 shl 16) or 0, large (0 shl 16) or 0
push 0
call sub_10CDD
call _grx_put stdcall, 0
pop cx
push 0
call sub_110ED
call _grx_free stdcall, 0
pop cx
push 0Ah
call _frame_delay