Repository navigation
Fx reboot, WIP - #299
Draft
trethaller wants to merge 218 commits into
Draft
Fx reboot, WIP#299trethaller wants to merge 218 commits into
trethaller wants to merge 218 commits into
Conversation
vLerp folds into the existing flat values when it matches one of them (the usual cases evaluate exactly as before), and falls back to VLerp, which getFast evaluates, instead of a non flat VAdd/VMult. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Params are stored under their plain name (scale, startSpeed...), one mode per component: Constant, Range, Curve, RandomCurve, CurveRange or unset, the shapes being a curve referenced by path or an easing (EmitterParam). Particle shaders under an emitter get the same model (Shader.particleParams), colors keep their curves. Old files are upgraded on load into equivalent modes (EmitterUpgrade) and saved in the new format (props.paramsVersion). Upgraded emitters keep the random slot layout of the old code (skippedRandomSlots), so they draw the same randoms. The animation curves of the spawn and multiplier params, and of the emitter settings, keep multiplying the value by name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nes on load An animation curve (over the FX time) is now the value of the property: the object transforms (position, scale, rotation in degrees) of FX and FX2D, the local rotation offset (degrees), the shader params out of the emitters, the emitter settings, spawn params (value, min, max) and multipliers. The life time can be animated too. The emitter params reference their animation curves by path (Emitter / Emitter2D.animCurves, saved in props.animCurves), curve names carry no meaning there. The FX objects and shaders still find theirs by name. Curves are saved with a version; the ones without it are upgraded on load (AnimUpgrade, old format only), on the raw data from FX.load / FX2D.load and the emitter load: the old constants are baked into the keys (exact for the linear cases, a Reference curve takes them in its scale / offset, a Blend curve bakes its children, the curves referencing a baked one are compensated), the old emitter curves are bound by path where they are (a range gets a second curve referencing the first). The rotation / scale of an object composed with a base rotation is folded exactly when the base rotation allows it, re-baked from samples otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An animation curve holds the value of the property: a new track starts with a key at the current value of the property (transform, shader param, light, renderer FX field, emitter setting or spawn / multiplier bound). The tracks of the emitter params are bound to them by path (animCurves), a range component gets a min and a max track. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Overrides saved from now on carry `#anim` (Diff.apply skips the `#` fields of a diff root). Old overrides set old curve values and the properties they were composed with: Reference.applyOverrides marks the curves they set as old and, when the referenced .fx is already upgraded, puts the curves of the prefabs they touch back in the old format (AnimUpgrade.legacyOverride, the inverse of the exact bakes), so the upgrade on load bakes them with the overridden values. A spawn range min that references its max follows the re-baked bounds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…he transform, tiny base angles count as none Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Value with a 4th component was always a color in the data (no `:w` curve in the games, only `:a`): VVector is x, y, z (2D and 3D), VColor r, g, b, a next to VHsl. getVectorValue no longer reads `:w` curves, getColorValue and the particle shader params of 4 components build a VColor (same evaluation). The emitter params have 3 components at most (EmitterParam.COMPONENTS). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A random between two curves is the Curve Range mode of the emitter params (a curve of two datas). The migration turns the other random blends into what the old runtime read: a spawn param becomes a range with its two child curves as bounds, a setting its first child curve (it read the random of the first particle), any other curve its own keys. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…atas CurveBlendMode is an enum saved by name: None, Blend (two datas blended by `param`), Range (two datas, the Curve Range of the emitter params) and Reference (`refPath`, no keys saved). A blend has no child curves anymore, the timeline edits each of its datas. The migration writes the new curve format (it was converted by `Curve.load`), and drops the curves under a plain curve, never read. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A param in a curve mode stores no curve: its curve is the child named after the param and component (`partScale`, `partRotation:z`), the first enabled one, like the other curves of an emitter. The shader particle params are the names of their curves (`particleParams`). Changing the mode removes the curve, a curve mode whose curve was deleted shows and saves as the default. Renames: the params `partX` (their runtime field stays `x`), `seedGroup` -> `seed`, `scaleOverTime` / `orbitSpeedOverTime` -> `scaleMultiplier` / `orbitSpeedMultiplier`, and in the code the plain fields are properties (`PROPERTIES`, `PropertyDef`), the fields with modes params (`PARAMS`, `ParamDef`), `InstanceDef` -> `ParticleDef`. The migration renames the curves the old runtime read, the unread ones keep their old name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…RandomColor + useRandomGradient Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only used by one unused Farever FX. The migration removes these curves, with a warning. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
timeScale, burstInterval, emitRateChangeTime, emitStartAngle/emitEndAngle (2D), emitDomeHeight, animationCycles, partMaxSpeed; their curves renamed by the migration. Labels: Dampen, Lock Axis, Stretch By Velocity, Kill Chance On Collision, Particle Scaling, group Emission. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # hide/kit/Slider.hx # hrt/prefab/fx/Emitter.hx # hrt/prefab/fx/EmitterHelper.hx
The prefix tells the clock of a curve: the Particle params, read over the particle life, are `partX`; the Spawn params and the properties, read over the emitter time, are not (`lifeTime`, `startSpeed`, `startWorldSpeed`, renamed by the migration). A param's name is also the field of its value in the emitter object: ParticleDef is removed, the particle param values are fields of EmitterObject / EmitterObject2D like the others, and the macro no longer strips the prefix. The spec and comments say emitter time where the emitter curves were said to be over the FX time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… (no copy of the keys on FX play) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ut rotation - A single `scale` curve puts the same Value on x, y and z: it is evaluated once (3 times since VectorAnimation, once with the scalar Value of master). About half of the animated objects of Farever have one. - `m.rotate` is skipped when the object has no rotation curve and no base rotation. Why VectorAnimation (a Value per axis, null for none) and not a Value all the way (VVector) for the transforms: - Since the curves hold the value they animate (794ca88), an axis without a curve keeps the value of the prefab: each axis is a field of its own (x, scaleY, rotationZ...), and partial animations are common (scale or position on one or two axes). - A VVector has no missing component: the prefab value would be copied in as a VConst when the animations are built, so an edit of that field in the editor would not show until they are rebuilt (or the editor would have to rebuild them on every transform change). The null reads the field at each sync. - Shader vectors and colors stay VVector / VColor: one field, replaced as a whole by its curves, a missing component a constant (0, 1 for colors), as before the migration (their curves were never multiplied, nothing re-baked). - Plain curves instead of Values on the FX side would duplicate the parameter and blend evaluation of the Evaluator, for no runtime gain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… no copies The emitter objects (3D and 2D) keep a `prefab` field, the clone made for this instance, and read the plain properties from it when they use them: the ~40 copies of `updateInstance` and their duplicate fields are removed (with their drifted defaults). The objects keep the `Value`s built by `makeValues`, overridable at runtime (`emitRate = VConst(10)`), and their state (`emitScale`, the rate state), grouped like the inspector. The random colors are blended from the prefab arrays. Game code changes a property on `e.prefab` (spec: Runtime). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Setting loop writes it to every data (a blend or a Curve Range samples each one with its own), and loading takes the one of the first data. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only short comments where the code needs one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`particleParams` of a shader under an emitter is saved by param name, a mode or a vector of component modes (`{ alpha: { mode: "Curve" }, UVOffset: { y: { mode: "Curve" } } }`) instead of a list of curve names, so that other modes can be added without another migration. In memory a map of the modes by curve name (`alpha`, `UVOffset:y`), null without any. The migration writes the new format.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
At the end of the upgrade, the numbers that were not in the data are written with 6 significant digits, 0 under 1e-6, removing the float noise of the bakes; the ones of the data are kept as they are. A RandomCurve spread negligible next to the other one (the overshoot of the curve beyond its keys) is 0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
randomColor1 / randomColor2 (and the color of Emitter2D) are RGB ints, as the other colors of the prefabs: their alpha was never read. The migration converts the arrays, rounded to 8 bits. The kit edits a PColor prop as an int when its value is one, as an array otherwise. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts: # hrt/prefab/fx/Emitter.hx
…om rate fixed Params are plain Values for every kind, SpawnValue is gone. The kinds only differ by their clock and their random: Particle (over the particle life, random per particle), Spawn (read at spawn, emitter time, random per particle), Emission (emitter time, random drawn by the emitter: a hash of the seed and the step, the same whatever the ticks). Every kind takes Constant, Range, Curve, RandomCurve and CurveRange; the curve of a param is always named after its component (no more `:min` / `:max` curves). Random slots keep the old order (Particle, then Spawn), Emission takes none. - The rate is one Emission param: InfinityRandom, emitRateMin / emitRateMax are gone. A random rate ramps to a new value every Rate Change Time (the old ramp went away from its target and could pause the emission). - Particles Per Burst is an Emission param: a Range draws an integer count per burst, both bounds included. - 3D Duration stops at its duration, as 2D (it kept emitting at its last rate). - Evaluator.getAtRandom evaluates a value with a given random; getFast shares its body (an inlined callback). - Editor: the curves of the Spawn / Emission params are modes, edited inline over the emitter time, no animation tracks. - Migration: spawn (k ± a)·c becomes RandomCurve (exact, parameter curves included, references copied), a spawn random blend a Curve Range, the rate and burst count curves a Curve mode, InfinityRandom a Range or a Curve Range. - Spec updated (kinds, modes, param curves, upgrade rows). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…n looping FX - A Follow sub-emitter that stops emitting no longer crashes: it is in the list of its particle until the particle dies, only a sub-emitter in its parent's list is auto removed. - Burst in a looping FX: the bursts before the tick of the loop are done, the first burst of each loop is no longer skipped. - BurstDuration in a looping FX: the loop tests its new time against the duration (it used the previous loop's), it emits on every loop. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… of scale upgraded to Point Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…for both The emitter colors are ARGB ints, alpha read (the inspector edits an int PColor with its alpha); the migration makes the old ones opaque, their alpha was never read. - Fade Color (fadeColorMode, fadeColor1 / fadeColor2, fadeGradient): a color over the particle life, from a start color to an end color or along a gradient. Default: white to transparent white. - The random color and the fade color multiply the pixel color, alpha included, in a single hrt.shader.ParticleShader added to the batch when one is set (lazily, by its first feature). It reads the per-particle random of BaseEmitter: no per-particle color on the CPU, ColorMult and ParticleInstance.colorMult are gone. Its modes are hxsl enum consts, its settings are read at init. Meant to take over ParticleColorRandom, ParticleColorLife... - RandomColorMode moved into Emitter.hx (used by both settings). - Emitter2D: ARGB colors, alpha read. - Spec: Colors section. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The switch on the rate mode in getHiddenFields had no null case: an unset rate (default value) read _hx_index of null in JS. The check is also split for readability: a random rate mode, and an emit type that reads the rate. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.