From 5f4f5d87dc8803a6ecb9a75e8fd547af88fc2923 Mon Sep 17 00:00:00 2001 From: nmlgc Date: Tue, 3 Dec 2019 22:45:08 +0100 Subject: [PATCH] [Decompilation] [th03] Shot update and render functions Meh, can't overload arithmetic operators that take a Subpixel without generating a needless load and store, even with -Z. But heck, slightly uglifying subpixel/subpixel arithmetic is exactly the right trade-off. Completes P0061, funded by Touhou Patch Center. --- Makefile.mak | 4 +- Research/Borland C++ decompilation.md | 22 ++++-- th03/main_01.cpp | 54 +++++++++++++ th03/math/subpixel.hpp | 4 + th03/shots.hpp | 3 + th03_main.asm | 105 +------------------------- 6 files changed, 81 insertions(+), 111 deletions(-) create mode 100644 th03/main_01.cpp diff --git a/Makefile.mak b/Makefile.mak index a94ce2ef..81c9d4e8 100644 --- a/Makefile.mak +++ b/Makefile.mak @@ -81,8 +81,8 @@ bin\th03\op.exe: bin\th03\op.obj th03\op_02.c $** | -bin\th03\main.exe: bin\th03\main.obj th03\sprite16.cpp - $(CC) $(CFLAGS) -ml -DGAME=3 -nbin\th03\ -eMAIN.EXE @&&| +bin\th03\main.exe: bin\th03\main.obj th03\main_01.cpp th03\sprite16.cpp + $(CC) $(CFLAGS) -ml -Z -DGAME=3 -nbin\th03\ -eMAIN.EXE @&&| $** | diff --git a/Research/Borland C++ decompilation.md b/Research/Borland C++ decompilation.md index debc8346..57c10cee 100644 --- a/Research/Borland C++ decompilation.md +++ b/Research/Borland C++ decompilation.md @@ -2,10 +2,10 @@ | | | |-|-| -| `DX` | First 8-bit variable declared *if no other function is called* | +| `DX` | First 8-bit variable declared *if no other function is called*
Second 16-bit variable declared *if no other function is called* | | `[bp-1]` | First 8-bit variable declared *otherwise* | | `SI` | First 16-bit variable declared | -| `DI` | Second 16-bit variable declared | +| `DI` | Second 16-bit variable declared *if other functions are called* | Example: @@ -64,10 +64,16 @@ inline optimally though: ## C++ -* Every class method that returns `void` inlines to the ideal representation. -* Every class method that returns `*this` inlines to the ideal representation - *only at the first nesting level*. Example: A class method calling an - overloaded operator returning `*this` will generate (needless) instructions +Class methods inline to their ideal representation if all of these are true: + +* returns `void` || (returns `*this` && is at the first nesting level of + inlining) +* takes no parameters || takes only built-in, scalar-type parameters + +Examples: + +* A class method (first nesting level) calling an overloaded operator (second + nesting level) returning `*this` will generate (needless) instructions equivalent to `MOV AX, *this`. Thus, any overloaded `=`, `+=`, `-=`, etc. operator should always return `void`. @@ -75,8 +81,8 @@ inline optimally though: custom types with overloaded assignment operators, with the resulting code generation being indistinguishable from equivalent C preprocessor macros. -* Returning *anything else* will first store that result in `AX`, leading any - branches at the call site to then refer to `AX`. +* Returning *anything else* but `void` or `*this` will first store that result + in `AX`, leading any branches at the call site to then refer to `AX`. **Certainty**: Maybe Borland (not Turbo) C++ has an optimization option against it? diff --git a/th03/main_01.cpp b/th03/main_01.cpp new file mode 100644 index 00000000..095a26f3 --- /dev/null +++ b/th03/main_01.cpp @@ -0,0 +1,54 @@ +/* ReC98 + * ----- + * Code segment #1 of TH03's MAIN.EXE + */ + +extern "C" +{ +#include "pc98.h" +#include "th03/sprite16.hpp" +#include "th03/playfld.hpp" +#include "th03/shots.hpp" + +void pascal near shots_update(void) +{ + shotpair_t near *shotpair = shotpairs; + for(int i = 0; i < SHOTPAIR_COUNT; i++, shotpair++) { + if(shotpair->flag) { + shotpair->topleft.y.v += shotpair->velocity_y.v; + if(shotpair->topleft.y.v <= to_sp(-1.0f)) { + shotpair->flag = 0; + } + } + } +} + +void pascal near shots_render(void) +{ + shotpair_t near *shotpair = shotpairs; + + sprite16_put_w = SHOT_W; + sprite16_put_h = SHOT_H; + sprite16_clip_left = 0; + sprite16_clip_right = RES_X - 1; + + for(int i = 0; i < SHOTPAIR_COUNT; i++, shotpair++) { + if(shotpair->flag) { + int so = shotpair->so_anim + shotpair->so_pid; + int left = playfield_fg_x_to_screen( + shotpair->topleft.x, shotpair->pid + ); + int top = shotpair->topleft.y.to_screen() + PLAYFIELD_Y; + + sprite16_put(left + 0, top, so); + sprite16_put(left + SHOTPAIR_DISTANCE, top, so); + + shotpair->so_anim += SHOT_VRAM_W; + if(shotpair->so_anim >= (SHOT_VRAM_W * SHOT_SPRITE_COUNT)) { + shotpair->so_anim = 0; + } + } + } +} + +} diff --git a/th03/math/subpixel.hpp b/th03/math/subpixel.hpp index b6897d12..88c17322 100644 --- a/th03/math/subpixel.hpp +++ b/th03/math/subpixel.hpp @@ -26,6 +26,10 @@ public: void operator =(float screen_v) { v = static_cast(to_sp(screen_v)); } + + T to_screen() const { + return v >> 4; + } }; template struct SPPointBase { diff --git a/th03/shots.hpp b/th03/shots.hpp index 9025a1df..2b31047c 100644 --- a/th03/shots.hpp +++ b/th03/shots.hpp @@ -23,3 +23,6 @@ struct shotpair_t { #define SHOTPAIR_COUNT 32 extern shotpair_t shotpairs[SHOTPAIR_COUNT]; + +void pascal near shots_update(void); +void pascal near shots_render(void); diff --git a/th03_main.asm b/th03_main.asm index fd8e0f4e..8d650b16 100644 --- a/th03_main.asm +++ b/th03_main.asm @@ -289,7 +289,7 @@ loc_977E: call p2_1F332 call p2_205D2 call sub_B7E5 - call sub_E83F + call shots_update mov byte ptr word_1FE88, 0 mov byte ptr word_23AF0, 0 call p1_2028C @@ -350,7 +350,7 @@ loc_986C: mov byte ptr word_1FE88, 1 mov byte ptr word_23AF0, 28h ; '(' call p2_1F33A - call sub_E86A + call shots_render call sub_164DA call sub_1837C call sub_B80B @@ -9078,105 +9078,8 @@ loc_E83B: retn sub_E737 endp - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_E83F proc near - push bp - mov bp, sp - push si - mov si, offset _shotpairs - xor dx, dx - jmp short loc_E862 -; --------------------------------------------------------------------------- - -loc_E84A: - cmp [si+shotpair_t.flag], 0 - jz short loc_E85E - mov ax, [si+shotpair_t.velocity_y] - add [si+shotpair_t.topleft.y], ax - cmp [si+shotpair_t.topleft.y], -16 - jg short loc_E85E - mov [si+shotpair_t.flag], 0 - -loc_E85E: - inc dx - add si, size shotpair_t - -loc_E862: - cmp dx, SHOTPAIR_COUNT - jl short loc_E84A - pop si - pop bp - retn -sub_E83F endp - - -; =============== S U B R O U T I N E ======================================= - -; Attributes: bp-based frame - -sub_E86A proc near - -@@top = word ptr -6 -@@left = word ptr -4 -@@sprite_offset = word ptr -2 - - enter 6, 0 - push si - push di - mov si, offset _shotpairs - mov _sprite16_put_w, (SHOT_W / 16) - mov _sprite16_put_h, SHOT_VRAM_H - mov _sprite16_clip_left, PLAYFIELD1_CLIP_LEFT - mov _sprite16_clip_right, PLAYFIELD2_CLIP_RIGHT - xor di, di - jmp short loc_E8EF -; --------------------------------------------------------------------------- - -loc_E88E: - cmp [si+shotpair_t.flag], 0 - jz short loc_E8EB - mov al, [si+shotpair_t.so_anim] - mov ah, 0 - add ax, [si+shotpair_t.so_pid] - mov [bp+@@sprite_offset], ax - push [si+shotpair_t.topleft.x] - mov al, [si+shotpair_t.pid] - mov ah, 0 - push ax - nopcall playfield_fg_x_to_screen - mov [bp+@@left], ax - mov ax, [si+shotpair_t.topleft.y] - sar ax, 4 - add ax, PLAYFIELD_Y - mov [bp+@@top], ax - call sprite16_put pascal, [bp+@@left], ax, [bp+@@sprite_offset] - mov ax, [bp+@@left] - add ax, SHOTPAIR_DISTANCE - call sprite16_put pascal, ax, [bp+@@top], [bp+@@sprite_offset] - mov al, [si+shotpair_t.so_anim] - add al, SHOT_VRAM_W - mov [si+shotpair_t.so_anim], al - cmp [si+shotpair_t.so_anim], SHOT_SPRITE_COUNT * SHOT_VRAM_W - jb short loc_E8EB - mov [si+shotpair_t.so_anim], 0 - -loc_E8EB: - inc di - add si, size shotpair_t - -loc_E8EF: - cmp di, SHOTPAIR_COUNT - jl short loc_E88E - pop di - pop si - leave - retn -sub_E86A endp - + SHOTS_UPDATE procdesc pascal near + SHOTS_RENDER procdesc pascal near main_01_TEXT ends ; ===========================================================================