Fortress.alm from Rance IX uses an MPEG-2 Program Stream containing
MPEG-1 video and MPEG-1 Layer II audio. As far as I checked, it is the
only .alm movie released in Japan that does not use an MPEG-1 Program
Stream.
The existing pl_mpeg decoders support its elementary streams, but the
demuxer rejects its MPEG-2 pack and PES headers. Extend the demuxer to
parse those headers and the PTS/DTS combinations used by Fortress.alm.
Replace direct one-shot zlib compression and decompression calls with
the libsys4 wrappers. Use exact-size decompression where file formats
provide the uncompressed size.
File2.c continues to depend directly on zlib because it uses streaming
inflate.
When NumLock is disabled, Windows reports numpad keys as navigation
virtual-key codes in the WM_KEYDOWN message. SACT2 games rely on this
behavior.
Translate SDL keypad scancodes to the corresponding SACT key codes in
that state, and map keypad Enter to VK_RETURN.
Fixes#359.
Add the following commands to the debugger:
3d list [all] List plugins and instances
3d plugin [<plugin>] Show or select the current plugin
3d show [<instance>] Dump plugin or instance state
3d set <instance> draw <0|1> Enable or disable drawing
3d set <instance> pos <x> <y> <z> Set the instance position
3d help Show command help
The show and set commands operate on the current plugin. If only one
plugin exists, it is selected automatically. Changes made with set are
rendered immediately.
If AddCreateCGToProcess fails for a missing CG, no create op is added to
the construction process. Game scripts still add drawing operations and
then build the process, leaving those operations with no destination
texture and causing an incomplete framebuffer error.
This makes construction build operations return false as soon as an
operation cannot be executed.
Fixes#356.
Game-specific .xsys4rc files are loaded from the game directory, so
relative paths in that file are most useful when interpreted from the
same directory. This allows patches that ship external fonts to
reference them with relative paths.
In both TapirEngine and SealEngine an instance is outlined only when the
global edge draw option and its per-instance edge flag are both on. The
per-instance flag is exposed via Set/GetInstanceDrawParam, whose edge
index differs by engine (Tapir 0, Seal 2).
For the global option the engine only distinguishes on/off, so drop the
RE_draw_edge_mode enum.
In SealEngine the outline length and color are plugin-wide values set
via SetEdgeLength/SetEdgeColor, not the per-mesh .opr parameters used by
TapirEngine.
Only resolve the method when the function's signature matches the
delegate type, returning 0 otherwise.
Also, DG_SET / DG_NEW_FROM_METHOD / DG_ADD should not add function 0.
This implements the sky/middle/ground hemisphere ambient driven by
light_params[8..19].
SealEngine has no separate specular-light instance; its specular instead
shares the hemisphere light vector.
SealEngine manages a 41-float light parameter set (serialized as .lit
file) for tone mapping, hemisphere lighting, and light scattering. This
adds the storage and HLL plumbing, without wiring values into shaders.
- A DIRECTIONAL_LIGHT instance owns a parameter set, filled by loading a
.lit file (RE_instance_load).
- SealEngine.StoreInstanceLightParam() reflects that presets into the
plugin's master buffer, which is used by the renderer.
- SealEngine.LoadInstanceLightParam() copies the master back into an
instance, and Reset()/Set()/Get() operate directly on the master.
Some games (e.g. Rance 01, Rance 9) only export GetFlag and SetFlag, so
Init() is never called. Initialize from _PreLink with a default save
file name in that case.
In TapirEngine, CalcIntersectEyeVec() only worked on models with a
"collision" mesh. In SealEngine, a raycast collider is built from the
union of meshes flagged HeightDetection=true in .opr.
Also return the nearest intersection instead of the first.
The EMISSIVE and ENV_MAP diffuse modes did not apply the ambient term or
vertex color (color_mod) to the fragment. In the original TapirEngine /
SealEngine, all diffuse modes contribute ambient and vertex color.
This fixes a bug where the movement/attack range indicator color did
not change in battle scenes.
SetInstanceDiffuse has two roles depending on the instance type: for
directional lights it is the light color, and for meshes it is a
multiplier on the mesh color. xsystem4 honored only the former.
Treat inst->diffuse as color multiplier, via the diffuse_mod uniform.
This adds a helper that resets every per-draw uniform to a neutral
default and call it at the start of the billboard, .pae and .3de paths.
This fixes uv_scroll and use_blend_texture leaks from a previously
rendered model.
KeepPreviousView and its mode are purely a rendering performance knob
(incremental rendering optimization). Toggling the mode never affects
rendering correctness, so leaving these unimplemented is harmless and
warning about them is just noise.
PE_Reset() zeroed the controller stack, leaving it with no default
controller. Since PE_Reset() does not clear parts_engine_initialized,
the subsequent PE_Init() returns early so the stack stays empty.
Reset the stack with ctrl_stack_init() instead, which re-creates the
default controller. ctrl_stack_fini() is now unused and removed.
Save a reduced copy of the main surface to a file. The image is written
as QNT under the save directory.
To avoid aliasing at large reductions, the surface is downscaled by
repeatedly halving before the final stretch.
At spawn, init_particle() samples its fixed properties from a
deterministic PRNG into s3de_particle, so playback is reproducible.
Each frame, update_object_states() interpolates the emitter's animated
properties into s3de_object_state.
To draw, render_s3de_effect() combines the two: for each live particle
s3de_billboard_world_transform() or s3de_mesh_world_transform() derives
a world matrix from the lifetime state computed by eval_particle(),
together with a posture basis that orients the quad or mesh. Objects are
drawn sorted by distance from the camera.
.3de is the particle/effect format used by SealEngine. Like the
ReignEngine's .pae, it is a text format describing an effect as a set of
emitters, but the two differ enough in design that .3de lives in its own
file (s3de.c) rather than being folded into particle.c.
This commit lays the groundwork:
- Parse .3de text.
- Integrate effect loading, playback, and caching into the existing
infrastructure.
- Apply the camera object's per-frame override to RE_camera.
- Play the companion sound asset.
Billboard and polygon-object rendering will be added separately.
The original {Reign,Tapir,Seal}Engine apply motion bones to model bones
purely by array position, never consulting bone name or bone_id.
This fixes bone animation of "Shizuka & Nagi" model in Rance 9.