Commit Graph

25 Commits

Author SHA1 Message Date
nmlgc 35ef90f4d1 [Reduction] Page flipping
Funded by -Tom-.
2018-12-30 00:16:18 +01:00
nmlgc 6a6ce47c56 [Reduction] EGC-powered VRAM region copies
Funded by -Tom-.
2018-12-29 17:03:26 +01:00
nmlgc 41622254a8 [Reverse-engineering] EGC register writes
Funded by zorg.
2018-12-25 23:45:24 +01:00
nmlgc 07e466cf3b [Reverse-engineering] [th01/th02/th04/th05] Player hit flag
Funded by zorg.
2018-12-15 22:57:36 +01:00
nmlgc 43001161e3 [Maintenance] Fix any whitespace issues in our own code 2015-09-07 15:44:48 +02:00
nmlgc 14e69ceb6d [C decompilation] [th01] VSync interrupt handler
Time to get back into this.
2015-09-05 22:33:07 +02:00
nmlgc 92979e8f31 [C decompilation] [th02] Code segment #2 of all three executables
Only one code segment left in both OP and FUUIN! its-happening.gif

Yeah, that commit is way larger than I'm comfortable with, but none of these
functions is particularly large or difficult to decompile (with the exception
of graph_putsa_fx(), which I actually did weeks ago), and OP and MAIN have
their own unique functions in between the shared ones, so…
2015-03-14 23:25:50 +01:00
nmlgc 44327e9305 [C decompilation] [th01/reiiden] 2D vector construction
Which, for some reason, is also found in the MAIN.EXE of every later game
in between completely unrelated hardware and file format functions.

Separate commit because it has its own segment in REIIDEN.EXE, and because
coming up with the nice function names took pretty long, since I haven't done
anything involving trigonometry in the past 5 years...
2015-03-13 23:03:39 +01:00
nmlgc e0d90dbdc3 [C decompilation] [th01] Text mode functions
Yet another set of questionable C reimplementations of master.lib functions to
waste my time. And half of them, including z_text_(v)putsa, aren't even called
anywhere.
2015-03-11 23:29:58 +01:00
nmlgc 6d2fa9f077 [C decompilation] [th01/reiiden] Randomly shaped VRAM copy functions, #1
So apparently, TH01 isn't double-buffered in the usual sense, and instead uses
the second hardware framebuffer (page 1) exclusively to keep the background
image and any non-animated sprites, including the cards. Then, in order to
limit flickering when animating the bullet, character and boss sprites on top
of that (or just to the limit number of VRAM accesses, who knows), ZUN goes to
great lengths and tries to make sure to only copy back the pixels that were
modified on plane 0 in the last frame.

(Which doesn't work that well though. When you play the game, you still notice
tons of flickering whenever sprites overlap.)

And by "great lengths", I mean "having a separate counterpart function for
each shape and sprite animated which recalculates and copies back the same
pixels from plane 1 to plane 0", because that's what the new functions here
lead me to believe. Both of them are only called at one place: the wave
function on the second half of Elis' entrance animation, and the horizontal
masked line function for Reimu's X attack animations.
2015-03-10 17:39:00 +01:00
nmlgc 519e24c459 Rename the *_copy_region_* functions to *_copy_rect_*
TH01 copies a lot of different shapes from plane 1 to 0, so "region" feels
awfully unspecific.
2015-03-10 14:18:28 +01:00
nmlgc 44ad3eb4bc [C decompilation] [th01/fuuin] Slow 2x VRAM region scaling
This function raises one of those essential questions about the eventual ports
we'd like to do. I'll explain everything more thoroughly here, since people
who might complain about the ports not being faithful enough need to
understand this.

----

The original plan was aim for "100% frame-perfect" ports and advertise them as
such. However, the PC-98 is not a console with fixed specs. As the name
implies, it's a computer architecture, and a plethora of different, more and
more powerful PC-98 models were released during its lifespan. Even if we only
consider the subset of products that fulfills the minimum requirements to run
the PC-98 Touhou games, that's still a sizable number of systems.

Therefore, the only true definition of a *frame* can be "everything that is
drawn between two Vsync wait calls". Such a *frame* may contain certain
expensive function calls, and certain systems may run these functions slower
than the developer expected, thus effectively leading to more *frames* than
the developer explicitly specified.

This is one of those functions.

Here, we have a scaling function that appears to be written deliberately to
run very slow, which ends up creating the rolling effect you see in the route
selection and the high score and continue screens of TH01. However, that
doesn't change the fact that the function is still CPU-bound, and neither
waits for Vsync nor is iteratively called by something that does. The faster
your CPU, the faster the rolling effect gets… until ultimately, it's faster
than one frame and therefore vanishes altogether. Mind you, this is true on
both emulators and real hardware. The final PC-98 model, the Ra43, had a CPU
clocked at 433 Mhz, and it may have even been instant there.
If you use more optimized algorithm, it also runs faster on the same CPU (I
tried this, and it worked beautifully)… you get the idea.

Still, it may very well be that this algorithm was not a deliberate choice and
simply resulted from a lack of experience, especially since this was ZUN's
first game.

That leaves us with two approaches to porting functions like these:

1) Look at the recommended system requirements ZUN specified, configure the
   PC-98 emulator accordingly, measure how much of the work is done in each
   frame, then rewrite the function to be bound to that specific frame rate…
2) …or just continue using a CPU-bound algorithm, which will pretty much
   complete instantly on any modern system.

I'd argue that 2) is actually the more "faithful" approach. It will run faster
than the typical clock speeds people emulate the games at, and maybe draw a
bit of criticism because of that, but it seems a lot more rational than the
approximation provided by 1). Not to mention that it's undeniably easier to
implement, and hey, a faster game feels a lot better than a slower one, right?

… Oh well, maybe we'll still encounter some kind of CPU-bound animation that
is so essential to the experience that we do want to lock it to a certain
frame rate…
2015-03-09 17:58:30 +01:00
nmlgc 160d4eb69f [C decompilation] [th01/op] [th01/reiiden] Random resident structure stuff 2015-03-07 17:43:39 +01:00
nmlgc 3b175c8980 [Reverse-engineering] [th01] ReiidenConfig structure 2015-03-06 23:04:25 +01:00
nmlgc 0fd7f14784 [C decompilation] [th01/op] Archive functions
Fuck TH02 and above and their bizarre assembly code that indeed appears to be,
uh, playfully "optimized" in the most inadequate of places, far away from the
innermost loop. It's ALWAYS just these one or two instructions I just can't
fucking get out of the C compiler, which lead to the conclusion that these
functions must have either been first compiled to assembly, then "fine-tuned"
and then linked into the executable…

… or I'm really just missing some obscure compiler setting.

At least with TH01, you can tell that the source language must have undeniably
been C++, and the decompilation is a breeze.
2015-03-05 23:12:14 +01:00
nmlgc 2ccad4f5a4 Centrally include master.h in ReC98.h 2015-03-03 06:47:23 +01:00
nmlgc 63299cdf42 [C decompilation] [th02/op] High score screen 2015-03-03 04:25:19 +01:00
nmlgc 37fc899c42 Add some useful increment and decrement macros
Which we'd really like to have for the highscore entering screen.
2015-03-01 22:52:25 +01:00
nmlgc d058666929 [C decompilation] [th02/maine] Rotating rectangle animation
Small detour into MAINE.EXE because it has all the juicy algorithms that will
explain the remaining unknown members of the highscore data structure, and
there's this one code segment here we need to get out of the way first.
2015-02-28 22:37:40 +01:00
nmlgc 2f1b287f3d [C decompilation] [th01] VRAM region copy via EGC
The same function appears unused in TH02's MAINE.EXE. Separate commit because
this was painful enough and we can link the C version into FUUIN.EXE right
now.
2015-02-27 23:11:47 +01:00
nmlgc a7235304ed Make the VRAM plane constants available to C 2015-02-24 22:16:31 +01:00
nmlgc 436f1c5722 [C decompilation] [th01] MDRV2 calls
Still missing mdrv2_resident() though, which we currently can't slot in there
due to that string constant constructor syntax. :/
2015-02-21 20:48:58 +01:00
nmlgc f861b0a5c3 [C decompilation] ZUNSOFT.COM, all of it
And, of course, it recompiles into the exact binary ZUN shipped in 1997.
Success! This project is so going to happen now.
2015-02-17 13:18:14 +01:00
nmlgc 07519a7238 [Reverse-engineering] 32-bit VRAM plane pointers
I've looked at every openly available piece of PC-98 documentation, and there
don't seem to be any official names for the individual planes. The closest
thing I could find was the description at

	http://island.geocities.jp/cklouch/column/pc98bas/pc98disphw2.htm

explaining that they represent the blue, red, green, and brightness component
when using the default PC-98 palette. However, these planes correspond to
nothing else but the 4 individual bits of the final index into the color
palette, and you can assign any color to every single palette slot. Therefore,
it's merely a convention that your own palettes don't have to follow (and in
Touhou, they don't).

Nevertheless, there doesn't seem to be an alternative, and the Neko Project II
source code uses the same B/R/G/E convention, so I'll go with that as well.
2015-02-10 23:43:34 +01:00
nmlgc f303222ffc Replace MASTERMOD with a per-game constant
Yup, packfiles finally proved that we really have a different set of changes
to master.lib in every game. Also, there are bound to be more of these game-
specific small changes to otherwise identical code in ZUN's own code.

And hey, no need to define that value in the build scripts anymore.

(I've also considered just copying modified versions into the individual game
subdirectories, but it's not too nice to expect people to diff them in order
to actually understand why these copies exist and where the changes actually
are.)
2014-11-15 02:03:41 +01:00