Skip to content

Commit

Permalink
[Decompilation] [th01] Stage objects: Background allocation and blitting
Browse files Browse the repository at this point in the history
Continuing the good error handling from the .PTN functions they're
based on… if only its sole caller actually cared.

Also: A sort-of limit of 102 objects per stage, just because someone
didn't use huge pointers where they would have been necessary…
:tannedcirno:

Part of P0128, funded by Yanga.
  • Loading branch information
nmlgc committed Nov 30, 2020
1 parent 27b3f29 commit 73f62a5
Show file tree
Hide file tree
Showing 7 changed files with 185 additions and 380 deletions.
2 changes: 1 addition & 1 deletion Makefile.mak
Expand Up @@ -53,7 +53,7 @@ bin\th01\op.exe: bin\piloadc.obj bin\th01\op.obj th01\op_01.cpp bin\th01\frmdely
$**
|

bin\th01\reiiden.exe: bin\piloadc.obj bin\th01\reiiden.obj th01\main_01.cpp th01\main_01_.cpp bin\th01\frmdely.obj bin\th01\vsync.obj bin\th01\ztext.obj bin\th01\initexit.obj bin\th01\graph.obj th01\main_07.cpp th01\main_08.cpp th01\main_09.cpp th01\grpinv32.cpp bin\th01\resstuff.obj th01\main_13.cpp th01\main_13_.cpp th01\main_14.cpp th01\main_15.cpp bin\th01\mdrv2.obj th01\main_19.cpp th01\main_20.cpp th01\main_21.cpp th01\main_23.cpp th01\main_25.cpp th01\main_27.cpp th01\main_30.cpp th01\main_38.cpp
bin\th01\reiiden.exe: bin\piloadc.obj bin\th01\reiiden.obj th01\main_01.cpp th01\main_01_.cpp bin\th01\frmdely.obj bin\th01\vsync.obj bin\th01\ztext.obj bin\th01\initexit.obj bin\th01\graph.obj th01\main_07.cpp th01\main_08.cpp th01\main_09.cpp th01\grpinv32.cpp bin\th01\resstuff.obj th01\main_13.cpp th01\main_13_.cpp th01\main_14.cpp th01\main_15.cpp bin\th01\mdrv2.obj th01\main_19.cpp th01\main_20.cpp th01\main_21.cpp th01\main_23.cpp th01\main_25.cpp th01\main_27.cpp th01\main_30.cpp th01\main_31.cpp th01\main_38.cpp
$(CC) $(CFLAGS) -ml -3 -Z -DGAME=1 -DBINARY='M' -nbin\th01\ -eREIIDEN.EXE @&&|
$**
|
Expand Down
8 changes: 1 addition & 7 deletions th01/formats/ptn.cpp
Expand Up @@ -107,13 +107,7 @@ void ptn_put_noalpha_8(screen_x_t left, vram_y_t top, int ptn_id)
vram_offset_t vram_offset = vram_offset_shift(left, top);
ptn_t *ptn = ptn_with_id(ptn_id);
for(pixel_t y = 0; y < PTN_H; y++) {
#define put_noalpha(vram_offset, w, ptn) \
VRAM_CHUNK(B, vram_offset, w) = (ptn->planes.B[y]); \
VRAM_CHUNK(R, vram_offset, w) = (ptn->planes.R[y]); \
VRAM_CHUNK(G, vram_offset, w) = (ptn->planes.G[y]); \
VRAM_CHUNK(E, vram_offset, w) = (ptn->planes.E[y]);
put_noalpha(vram_offset, PTN_W, ptn);
#undef put_noalpha
vram_put_ptn_planar(vram_offset, ptn);
vram_offset += ROW_SIZE;
}
}
Expand Down
6 changes: 6 additions & 0 deletions th01/formats/ptn.hpp
Expand Up @@ -93,6 +93,12 @@ extern bool ptn_unput_before_alpha_put;

// 32×32 access
// ------------
#define vram_put_ptn_planar(vo, ptn) \
VRAM_PUT(B, vo, ptn->planes.B[y], PTN_W); \
VRAM_PUT(R, vo, ptn->planes.R[y], PTN_W); \
VRAM_PUT(G, vo, ptn->planes.G[y], PTN_W); \
VRAM_PUT(E, vo, ptn->planes.E[y], PTN_W);

// Displays the given [ptn_id] at (⌊left/8⌋*8, top), disregarding its alpha
// plane.
void ptn_put_noalpha_8(screen_x_t left, vram_y_t top, int ptn_id);
Expand Down
101 changes: 101 additions & 0 deletions th01/main/stage/stageobj.cpp
@@ -1,2 +1,103 @@
extern "C" {
#include <malloc.h>
#include "platform.h"
#include "pc98.h"
#include "planar.h"
#include "th01/formats/ptn.hpp"
#include "th01/formats/stagedat.hpp"
}

#include "th01/main/stage/stageobj.hpp"

static const int TURRET_QUICK_INTERVAL = 100;
static const int TURRET_SLOW_INTERVAL = 200;

// Frees [stageobj_bgs] if non-NULL, then allocates new memory for the given
// number of stage object backgrounds.
ptn_error_t stageobj_bgs_new(int image_count)
{
if(image_count <= 0) {
return PE_IMAGE_COUNT_INVALID;
}
if(stageobj_bgs) {
farfree(stageobj_bgs);
}

// I suppose calloc() was chosen to conveniently reset the alpha planes?
// It's not like they're used anywhere, though...
//
// Using a far*() function here is actually correct, as it allows more
// than 64 KB to be allocated. Except that [stageobj_bgs] should have also
// been a `huge` pointer, to allow all this memory to be accessed using
// regular array subscripts... This way, the game can still only display
// up to 102 stage objects without glitches, and the wrap-around when
// writing to the 103rd background is guaranteed to corrupt the memory
// block header at the beginning of the returned segment.
stageobj_bgs = reinterpret_cast<ptn_t *>(
farcalloc(image_count, sizeof(ptn_t))
);
if(!stageobj_bgs) {
return PE_OUT_OF_MEMORY;
}
// Also, these factors should have maybe been casted to 32-bit...
// Multiplying two 16-bit values also truncates the result.
stageobj_bgs_size = (image_count * sizeof(ptn_t));
return PE_OK;
}

void stageobj_bgs_put_all(void)
{
int i;
for(i = 0; i < cards.count; i++) {
stageobj_bgs_put_8(cards.left[i], cards.top[i], (i + 0));
}
for(i = 0; i < obstacles.count; i++) {
stageobj_bgs_put_8(
obstacles.left[i], obstacles.top[i], (i + cards.count)
);
}
}

bool16 stageobj_bgs_free(void)
{
if(stageobj_bgs) {
farfree(stageobj_bgs);
stageobj_bgs_size = 0;
stageobj_bgs = NULL;
}
return 0;
}

#define vram_put_ptn_bg_fg(plane, vo, bg, fg, y, fg_mask, tmp) \
tmp = (~fg_mask & bg->planes.plane[y]); \
VRAM_PUT(plane, vo, ((fg->planes.plane[y] & fg_mask) | tmp), PTN_W);

void stageobj_put_8(screen_x_t left, vram_y_t top, int ptn_id, int bg_slot)
{
upixel_t y;
dots_t(PTN_W) fg_mask = 0;
dots_t(PTN_W) bg_dots_masked;
vram_offset_t vo = vram_offset_muldiv(left, top);

ptn_t *fg;
if(ptn_id != PTN_STAGEOBJ_NONE) {
fg = ptn_with_id(ptn_id);
}
ptn_t *bg = &stageobj_bgs[bg_slot];

if(ptn_id != PTN_STAGEOBJ_NONE) {
for(y = 0; y < PTN_H; y++) {
fg_mask = fg->alpha[y];
vram_put_ptn_bg_fg(B, vo, bg, fg, y, fg_mask, bg_dots_masked);
vram_put_ptn_bg_fg(R, vo, bg, fg, y, fg_mask, bg_dots_masked);
vram_put_ptn_bg_fg(G, vo, bg, fg, y, fg_mask, bg_dots_masked);
vram_put_ptn_bg_fg(E, vo, bg, fg, y, fg_mask, bg_dots_masked);
vo += ROW_SIZE;
}
} else {
for(y = 0; y < PTN_H; y++) {
vram_put_ptn_planar(vo, bg);
vo += ROW_SIZE;
}
}
}
38 changes: 38 additions & 0 deletions th01/main/stage/stageobj.hpp
Expand Up @@ -57,3 +57,41 @@ extern screen_y_t portal_dst_top;
// re-entering.
extern bool16 portals_blocked;
// --------------------

// Blitting
// --------
// Stationary stage objects are blitted to both VRAM pages, which makes it
// possible to efficiently unblit the other entities moving on top of them, by
// simply restoring pixels from VRAM page 1. Since the player can remove
// cards though, the backgrounds behind them also need to be stored somewhere.
// Storing only the 32×32 regions covered by the cards minimizes the memory
// needed for this, and doesn't require the full background .GRP to be stored
// in memory… which the PiLoad library can't do anyway.
// Since obstacles also need to be removed during a stage transition, their
// backgrounds are stored as well. This makes absolutely sure that a .GRP only
// needs to be blitted a single time, when entering a new scene.

// Planar<ptn_plane_t> would have been enough though, since there's no alpha
// plane to be snapped from VRAM anyway... Assumed by everything to contain
// [card_count] card backgrounds first, followed by [obstacle_count] obstacle
// backgrounds.
extern ptn_t *stageobj_bgs;
extern unsigned long stageobj_bgs_size;

// Frees [stageobj_bgs], if non-NULL. Always returns 0.
bool16 stageobj_bgs_free(void);

// Blits the backgrounds for all cards and obstacles at their respective
// positions, effectively removing those sprites from VRAM.
void stageobj_bgs_put_all(void);

// Blits both the stage object background with the given [bg_slot], and the
// given [ptn_id] on top, to (⌊left/8⌋*8, top) in a single blitting operation.
void stageobj_put_8(screen_x_t left, vram_y_t top, int ptn_id, int bg_slot);

// Blits the stage object background with the given [bg_slot] to
// (⌊left/8⌋*8, top).
#define stageobj_bgs_put_8(left, top, slot) \
stageobj_put_8(left, top, PTN_STAGEOBJ_NONE, slot)
#define PTN_STAGEOBJ_NONE 9999
// --------
6 changes: 6 additions & 0 deletions th01/main_31.cpp
@@ -0,0 +1,6 @@
/* ReC98
* -----
* Code segment #31 of TH01's REIIDEN.EXE
*/

#include "th01/main/stage/stageobj.cpp"

0 comments on commit 73f62a5

Please sign in to comment.