Commit Graph
1570 Commits
Author SHA1 Message Date
Nunuhara Cabbage 3012faa6ff Merge pull request #352 from kichikuou/lighting
SealEngine: Add lighting support
2026-06-20 06:22:14 -07:00
kichikuou 6dbb5baf19 SealEngine: Implement filmic tone mapping
Apply the Uncharted 2 tone curve [1] from light_params[0..7] as the
final fragment operation.

[1] https://filmicworlds.com/blog/filmic-tonemapping-operators/
2026-06-20 11:41:56 +09:00
kichikuou db8279ebc3 SealEngine: Implement hemisphere lighting
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.
2026-06-20 11:41:56 +09:00
kichikuou 250bc82818 SealEngine: Enable light scattering
Reuse ReignEngine's existing scattering shader code. The ls_* uniforms
are sourced from .lit parameters.
2026-06-20 11:41:56 +09:00
kichikuou 4843e4e87a SealEngine: add light parameter storage and HLL bindings
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.
2026-06-20 11:41:56 +09:00
kichikuou 1051294247 SealEngine: Implement SpecularColor and SpecularPower .opr attributes
Parse per-mesh SpecularColor and SpecularPower attributes from .opr
files, and apply them to specular lighting.
2026-06-20 11:41:56 +09:00
Nunuhara Cabbage fa98a76c42 Merge pull request #351 from kichikuou/msgskip
MsgSkip: Initialize in _PreLink when Init() is absent
2026-06-19 17:30:35 -07:00
kichikuou d073875d94 MsgSkip: Initialize in _PreLink when Init() is absent
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.
2026-06-18 08:10:49 +09:00
Nunuhara Cabbage 2b67a9e000 Merge pull request #350 from kichikuou/3d
3d: Various improvements for Rance 9
2026-06-14 13:28:48 -07:00
kichikuou b62edb7188 SealEngine: Support HeightDetection=true .opr attribute
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.
2026-06-13 20:30:45 +09:00
kichikuou 85547ef4f4 3d: Remove color_add uniform
Since the ambient term is now added unconditionally, the s3de per-object
additive color can be folded into instance_ambient.
2026-06-12 15:00:40 +09:00
kichikuou f108b7f436 3d: Apply ambient and vertex color across all diffuse modes
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.
2026-06-12 15:00:40 +09:00
kichikuou 90c3ab5008 3d: Apply per-instance diffuse to mesh color
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.
2026-06-12 15:00:40 +09:00
kichikuou 7b9565fe25 3d: Add reset_draw_uniforms() to prevent per-draw state leaks
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.
2026-06-12 15:00:40 +09:00
kichikuou 4dcc50d6ca 3d: Build models from MarmotModelEngine.Update()
In TapirEngine and SealEngine, model updates are drived by
MarmotModelEngine.Update(). RE_render() now only renders.
2026-06-12 15:00:40 +09:00
kichikuou 5c47ad5aae SealEngine: Implement ZWrite .opr attribute 2026-06-12 15:00:39 +09:00
Nunuhara Cabbage 062713f70e Merge pull request #349 from kichikuou/parts
Implement two PartsFuncs, and minor fixes
2026-06-11 17:22:02 -07:00
kichikuou 0e8bd36407 SACT2: Update draw plugins during TRANS_Update()
This fixes the issue where the 3D plugin freezes during transitions.
2026-06-10 17:21:04 +09:00
kichikuou 28554137cc Stoat/Chipmunk: Silence KeepPreviousView_Set/GetMode warnings
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.
2026-06-10 17:17:08 +09:00
kichikuou 32024bc805 PartsEngine: Fix "Invalid controller number" error after vm_reset
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.
2026-06-10 17:17:08 +09:00
kichikuou ec9bd95dc9 PartsEngine: Implement PartsFunc 3 (motion Pause/Resume)
Wire up PartsFunc 3 (PauseMotion) to a new PE_PauseMotion(). While
paused, PE_UpdateMotionTime stops advancing the motion clock.
2026-06-10 17:17:05 +09:00
kichikuou 8dee7d8658 PartsEngine: Implement PartsFunc 6 (SaveThumbnail)
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.
2026-06-10 17:17:01 +09:00
Nunuhara Cabbage 0f73ded483 Merge pull request #348 from kichikuou/3de
3de: Add support for billboard and polygon objects
2026-06-07 07:09:42 -07:00
kichikuou 847987ec1b 3de: Add support for billboard and polygon objects
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.
2026-06-04 09:41:49 +09:00
Nunuhara Cabbage ec4b608877 Merge pull request #347 from brombrom-hani/parts-sprite-deform
parts: impl sprite_deform for SetPartsCG
2026-06-01 17:55:27 -07:00
BromBrom-Hani 12735d5c8c parts: sprite_deform for SetPartsCG string index
Keeps the PE_SetPartsCG_by_string_index consistent with the rest of the SetPartsCG variants
2026-06-01 08:43:24 +02:00
Nunuhara Cabbage 22d58d977a Merge pull request #346 from kichikuou/3de-parser
SealEngine: Add .3de parser, effect framework, camera, and sound
2026-05-31 18:11:38 -07:00
Nunuhara Cabbage 20e0d00661 Merge pull request #345 from kichikuou/bone
3d: Match MOT bones to POL bones by array index
2026-05-31 18:10:21 -07:00
BromBrom-Hani a706a41dcb parts: impl sprite_deform for SetPartsCG 2026-05-31 12:22:36 +02:00
kichikuou bf0b2bb44f SealEngine: Add .3de parser, effect framework, camera, and sound
.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.
2026-05-31 08:22:01 +09:00
kichikuou 916daec6b2 3d: Match MOT bones to POL bones by array index
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.
2026-05-29 07:17:41 +09:00
Nunuhara Cabbage 1fcccb766c Merge pull request #344 from kichikuou/passed_time
PartsEngine: clamp passed_time to 0 in PE_UpdateComponent
2026-05-27 21:00:56 -07:00
kichikuou aa112849de Remove passed_time parameter from parts_render_update 2026-05-28 07:39:15 +09:00
kichikuou 8ca1a31ccc PartsEngine: clamp passed_time to 0 in PE_UpdateComponent
After loading a save, the game script may give a negative passed_time
because it computes the delta time using an absolute system.GetTime()
value stored in the save data.

This fixes hang on load in Rance 9.

This also removes the equivalent workaround in parts_render_update for
Rance 01, since the new clamp covers that case as well.
2026-05-27 12:42:50 +09:00
Nunuhara Cabbage 2c622bb331 Merge pull request #343 from kichikuou/mpr
SealEngine: Add .mpr (motion material keyframes) support
2026-05-25 19:07:24 -07:00
kichikuou c01a27583c SealEngine: Add .mpr (motion material keyframes) support
.mpr is an optional sidecar to .mot used by SealEngine, replacing .txa
used in ReignEngine / TapirEngine. While .mot drives bone poses, .mpr
drives material properties on a per-frame timeline.

Supported keys, all keyed by frame number:

  Object{MulAlpha,MulDiffuse,AddAmbient} : applied to the whole model
  Mesh{MulAlpha,MulDiffuse,AddAmbient}   : applied per named mesh
  MeshTextureAnime                       : swap diffuse texture index

Colors and alpha use linear interpolation between keys. Out-of-range
frames hold the nearest endpoint.

Mesh* tracks act as per-mesh tints and do not leak to other meshes
that happen to share a material. MeshTextureAnime is the exception:
it rewrites the shared material's diffuse slot, so all meshes using
that material animate in sync (e.g. in Rance 9, hanny_black_move.mpr
lists only hibana_R but hibana_L animates together).
2026-05-22 13:57:02 +09:00
Nunuhara Cabbage ced4daa331 Merge pull request #342 from kichikuou/camera
3d: Fix camera yaw direction and rotation order
2026-05-19 20:41:33 -07:00
kichikuou 9eee82c13b 3d: Fix camera yaw direction and rotation order
The camera view direction was computed incorrectly in two ways:

1. glm_euler (XYZ order) applies pitch around world X. The original
   engine uses YXZ where pitch is around the camera's local X after yaw.

2. SetCameraAngle negated the input yaw.
2026-05-20 07:10:41 +09:00
Nunuhara Cabbage f53ec98d53 Merge pull request #340 from kichikuou/emitter
Flat: Add particle emitter support
2026-05-18 22:19:56 -07:00
kichikuou 32f4253948 Flat: Guard against division by zero in particle time calculation 2026-05-19 11:38:36 +09:00
kichikuou cb0b969492 Flat: Add particle emitter support
This implements rendering of FLAT_LIB_EMITTER libraries: timed spawning,
per-particle motion, fade, and 3-axis rotation.

For each visible emitter, render_flat_emitter() builds an emitter base
matrix from the ancestor key stack so particles follow their parent
timelines. parent_key_mode chooses between filtering ancestor properties
via the emitter's inherit_* flags (SELECTIVE) and using ancestor poses
wholesale (ANCESTOR_CURRENT / ANCESTOR_AT_BIRTH). For each birth frame
in the lifetime window, parts_flat_foreach_emitter_particle() reseeds
the RNG from (rand_seed, birth_frame), making particles deterministic
across re-renders, and yields each particle's pose, which is composed
with the emitter transform and submitted as a quad through the standard
parts texture pipeline.
2026-05-19 07:12:11 +09:00
Nunuhara Cabbage 0030e28471 Merge pull request #339 from kichikuou/parts-3dlayer-z
Parts: Fix Z-order of 3DLayer and Movie parts
2026-05-16 07:46:35 -07:00
kichikuou 224db2f9cc Parts: Fix Z-order of 3DLayer and Movie parts
3DLayer and Movie parts use a SACT sprite as their render target (for
SealEngine output or movie frames). That sprite was registered into
the scene at z=0, so the content was drawn at z=0 instead of (or in
addition to) the parts engine's render path at the parts' configured Z.

Hide the bound SACT sprite from the scene so the parts engine is the
sole renderer of its texture, and add a parts_render case for 3DLayer
that composites the bound sprite's texture through parts_render_cg.
2026-05-16 12:44:17 +09:00
Nunuhara Cabbage 33d07c190e Merge pull request #338 from kichikuou/color-propagation
Flat: Fix color propagation for nested flat TIMELINE libraries
2026-05-12 17:11:52 -07:00
kichikuou a4dd6a42df Flat: Fix color propagation for nested flat TIMELINE libraries
Propagate parent keys' mul/add color parameters to child TIMELINE
library rendering.
2026-05-12 10:25:03 +09:00
Nunuhara Cabbage da268288c3 Merge pull request #337 from kichikuou/flat
Parts: Stop motion support and rendering fixes
2026-05-10 09:58:02 -07:00
kichikuou f535223988 Flat: Support angle_x/angle_y rotation and reverse_lr/reverse_tb
The original engine implements proper perspective projection, but we
use simpler orthographic foreshortening. In Rance 9, the visual
difference is barely noticeable.
2026-05-09 12:12:38 +09:00
kichikuou f9087eb7ac Flat: Fix area_x/area_y leaking into screen position
area_x/area_y select a sub-rectangle of the texture, but should not
shift the on-screen position. Translate the quad by (-area_x, -area_y)
to cancel the offset the sub-rect's top-left would otherwise introduce.
2026-05-07 12:42:08 +09:00
kichikuou 636743478c Flat: Propagate parent TIMELINE's draw_filter
A parent key's draw_filter had no effect on CG/STOP_MOTION leaves
inside descendant TIMELINE libraries. Resolve the effective filter
at each key (own if non-NORMAL, otherwise inherited) and thread it
through the render chain.
2026-05-07 12:18:35 +09:00
kichikuou a2f087b7f9 Flat: Add support for FLAT_LIB_STOP_MOTION
FLAT_LIB_STOP_MOTION represents a sprite animation as a sequence of CG
frames. A stop_motion library specifies a base CG file (e.g. "foo.png");
at load time, parts_flat_load() discovers numbered frame variants
("foo_01.png", "foo_02.png", ...) and builds a frame list.

At render time, the active frame is resolved from the local timeline
clock using three parameters:
  - span: number of timeline ticks each frame is displayed
  - loop_type: 0 = play once and stop at last frame,
               1 = loop forward,
               2 = ping-pong (forward then backward)
  - local: the timeline's current local time
2026-05-07 11:23:53 +09:00