This commit is contained in:
water111
2026-08-10 23:23:53 -07:00
parent 90d6ee7451
commit 91e4f0b3f8
8 changed files with 104 additions and 73 deletions
+1 -1
View File
@@ -16771,7 +16771,7 @@ the function that applies its ambient effect."
(deftype sprite-array-2d (basic)
((num-sprites int32 2 :offset-assert 4)
(num-valid int32 2 :offset-assert 12)
(vec-data pointer :offset-assert 20)
(vec-data (inline-array sprite-vec-data-2d) :offset-assert 20)
(adgif-data (inline-array adgif-shader) :offset-assert 24)
(pad uint128 4 :offset-assert 32)
(data uint128 1 :offset-assert 96)
+16 -15
View File
@@ -2,17 +2,18 @@
(in-package goal)
(bundles "ENGINE.CGO" "GAME.CGO")
(require "kernel/gkernel-h.gc")
(define-extern get-eye-block (function int int int))
(define-extern merc-eye-anim (function process-drawable none))
(define-extern update-eyes (function none))
;; The eye renderer generates eye textures with an aniamted eyelid, iris, and pupil.
;; It consumes animation data and renders the eye to a texture later used by merc/generic.
;; DECOMP BEGINS
;; One eye's animation state, packed into two vectors so consecutive keyframes can be interpolated
;; with two vector lerps. x and y steer the iris and pupil, lid controls eyelid closure, and the
;; second vector holds the three independent sprite scales.
;; Everything that can be animated/adjusted on a single eye as floats.
;; This can be driven from an animation or procedural blinking.
(deftype eye (structure)
((data vector 2 :inline)
(x float :overlay-at (-> data 0 x))
@@ -22,24 +23,24 @@
(pupil-scale float :offset 20)
(lid-scale float :offset 24)))
;; One live eye-rendering slot. process identifies its drawable, level selects the level texture
;; bucket or the common eye bucket, shaders points at its iris material, and random-time and blink
;; drive the automatic blink envelope applied to both animated eyes.
;; Characters with animated eyes add an eye-control
;; note: background color of the eye is set to the 0,0 texel of the iris.
(deftype eye-control (structure)
((process handle)
(random-time uint16)
(level uint16)
(blink float)
(shaders (inline-array adgif-shader))
((process handle) ;; process owning the eye
(random-time uint16) ;; blink countdown
(level uint16) ;; level owning the character, controls when eye textures are uploaded
(blink float) ;; blink state (shared between the left and right eye)
(shaders (inline-array adgif-shader)) ;; shaders for the iris, pupil, lid.
(left eye :inline)
(right eye :inline)))
;; Fixed pool indexed by the eye-slot stored in merc geometry.
;; It's strange that eye slots weren't dynamically assigned.
(deftype eye-control-array (basic)
((data eye-control 11 :inline)))
;; Reusable DMA/GIF packet headers for the eye sprites and adgif state, followed by the ten-sample
;; close-and-open blink envelope.
;; DMA templates, an optimization for generating the rendering DMA chain.
;; blink-table is the animation of closing, holding shut, and opening the eyelid.
(deftype eye-work (structure)
((sprite-tmpl dma-gif-packet :inline)
(sprite-tmpl2 dma-gif-packet :inline)
+8 -5
View File
@@ -3,11 +3,13 @@
(bundles "ENGINE.CGO" "GAME.CGO")
(require "kernel-defs.gc")
;; shadow-h is the "fake shadow" system. This draws a circular shadow on the ground.
;; It was later mostly replaced by shadow volumes based on simplified meshes.
;; A few things still use fake shadows, like projectiles.
;; DECOMP BEGINS
;; One circular projected shadow in the sprite renderer's three-quadword input format. Position and
;; scale occupy the first quadword; qx/qy/qz encode the ground-normal rotation with quaternion w
;; omitted, and flags select the shadow blend state.
;; Fake shadow record: location, orientation, and size.
(deftype fake-shadow (structure)
((px float)
(py float)
@@ -19,8 +21,9 @@
(flags int32))
:pack-me)
;; Double-buffered list of at most 32 shadows. Gameplay fills the active buffer while sprite drawing
;; consumes the previous one.
;; Double-buffered fake shadows. It doesn't seem like this is needed at all,
;; since sprite.gc ends up copying these into the DMA buffer directly, this may
;; be a leftover from an earlier rendering implementation.
(deftype fake-shadow-buffer (basic)
((num-shadows int32)
(data fake-shadow 32 :inline)))
@@ -3,31 +3,18 @@
(bundles "ENGINE.CGO" "GAME.CGO")
(require "kernel/gcommon.gc")
;; The "sparticle" system is the particle system.
;; Features
;; - Support for 2D particles (autosave icon, progress menu graphics)
;; - Support for 3D particles (many of the effects)
;; - Uses the "sprite" renderer to draw particles
;; sparticle (likely sprite - particle) is the particle system.
;; The "sparticle-launcher" code is the framework for describing particle effects
;; The "sparticle" code is the system that runs particles
;; Note that neither of these link particles to the process system. See part-tracker for that.
;; the description of a single particle is a "sparticle-launcher", which is constant data.
;; The *part-id-table* stores references to each sparticle-launcher, indexed by ID
;; The highest-level class here is sparticle-launch-control.
;; Each instance of a particle effect must have one of these.
;; For example, there would be one of these per eco-vent.
;; These store some state (a sparticle-launch-state) and a reference to a sparticle-launch-group
;; Multiple launch-controls can refer to the same launch-group.
;; A "sparticle-launch-group" describes a group of sparticle-launchers, as a single effect.
;; For example, there might be a sparticle-launch-group for an explosion which has
;; both fireball and smoke sparticle-launchers.
;; The *part-group-id-table* stores references to all sparticle-launch-groups
;; A sparticle-launch-group is a description of a particle effect.
;; It can contain multiple types of particles.
;; The `*part-group-id-table*` array stores a reference to every launch-group, indexed by group id.
;; Each launch-group is just a list of sparticle-launchers, stored as an index
;; A launcher is a single particle effect.
;; The `*part-id-table*` has references to all particle effects.
;; It contains a list of "field-init-specs". When the particle effect starts, the system
;; iterates through this list and sets parameters about particles.
;; A particle effect is described in a group of field : value declarations.
;; There are five types of fields:
;; misc fields
@@ -36,10 +23,9 @@
;; launch fields
;; weird fields
;; The built-in parameters can be used for many simple effects, but sometimes it is not enough.
;; You can provide a callback function to update the particle's state if needed.
;; these are arranged based on how the engine consumes.
;; These are the user-settable state variables for each particle effect
;; List of all settable fields and grouping helpers
(defenum sp-field-id
:type uint16
(misc-fields-start 0)
@@ -114,34 +100,48 @@
(spt-scalevel 66)
(spt-end 67))
;; How sp-init-fields! interprets an sp-field-init-spec when initializing a
;; field. Integer and floating-point fields store
;; initial + random-mult * (rand * random-range), where rand-vu returns [0, 1).
;; sp-flag controls how a field value is interpreted.
;; The int, float, float-int-rand options create a randomized number:
;; int: initial + truncate(rand * random-range) * random-mult
;; float: initial + rand * random-rangef * random-multf
;; float-int-rand: initial + truncate(rand * (random-range + 1)) * random-multf
(defenum sp-flag
:type uint16
(int 0) ;; integer field; the random term is truncated to an integer
(float 1) ;; floating-point field
(float-int-rand 2) ;; float with an integer-quantized random term
(int 0) ;; end result is truncated to integer
(float 1) ;; everything is float
(float-int-rand 2) ;; float with an integer-quantized random offset
(copy-from-other 3) ;; copy an earlier field at the negative offset in initial-value
(object 4) ;; raw object or label pointer, such as a sound-spec or :data payload
(symbol 5) ;; store the symbol's value
(launcher 6) ;; resolve initial-value as an index in *part-id-table*
(launcher 6) ;; treat initial-value as an index in *part-id-table*
)
;; options for an entire group
;; use-local-clock means the effect maintains its own clock.
;; this is used when effects have some explicit starting behavior,
;; for example an explosion might display fire at time 0 and smoke
;; at a later time. This is disabled for effects that need global
;; syncrhonization with other effects, like geysers.
;; always-draw disables view frustum culling for processing.
;; this is useful for particle effects that take a while to get
;; going, like a waterfall that drops particles from high up.
;; you woudln't want the waterfall to restart each time
;; the player looks away and back.
;; randomize-order "randomizes" the draw order of the particles
;; only used on the sentinel beach waterfall.
(defenum sp-group-flag
:bitfield #t
:type uint16
(use-local-clock 0)
(always-draw 1)
(screen-space 2)
(unknown-bit-01 3) ;; beach-part
(randomize-order 3)
)
;; DECOMP BEGINS
;; This describes the initial value and some more info for a single field
;; Note that there are overlays here and some values only make sense in some
;; cases.
;; This describes the initial value and randomization parameter
;; for a field.
(deftype sp-field-init-spec (structure)
((field sp-field-id)
(flags sp-flag)
@@ -157,6 +157,18 @@
(sym symbol :overlay-at initial-valuef)
(sound sound-spec :overlay-at initial-valuef)))
;; Definition of a particle effect as a list of fields.
;; birthaccum and soundaccum are two accumulators for birth and sound triggers.
;; Each time (launch-particles is called, it adds `num` to `birthaccum`. If the value
;; is over 1.0, it triggers a launch. If the launch succeeds, it decrements by 1.
;; There is no automatic retry, the intent is that you call (launch-particles on
;; each frame, and the game launches `num` particles per 1/60 of a second on average
;; (note that on PAL it's still num particles per 1/60th of a second)
;; soundaccum accumulates `sound-spec.num` per launch, when it reaches 1 it triggers
;; a sound.
;; The soundaccum is always shared between all instances of a sparticle-launcher.
;; If a particles is launched in a group with a state, it uses a state-local birthaccum.
;; Otherwise, it uses this birthaccum.
(deftype sparticle-launcher (basic)
((birthaccum float)
(soundaccum float)
@@ -179,7 +191,7 @@
;; One launcher in a group, with its timing and visibility parameters. Timing
;; uses 300 Hz ticks. period is the cycle length, with zero meaning continuous
;; launch; length is the active window within a cycle; and offset changes the
;; instance's phase. fade-after stops emission beyond that camera distance,
;; instance's phase. fade-after decreases emission beyond that camera distance,
;; while falloff-to is the distance where the linearly scaled emission rate
;; reaches zero. hour-mask suppresses emission during selected in-game hours.
(deftype sparticle-group-item (structure)
@@ -217,6 +229,7 @@
(declare-type sparticle-cpuinfo structure)
;; state of a single launcher
(deftype sparticle-launch-state (structure)
((group-item sparticle-group-item)
(flags sp-launch-state-flags)
@@ -233,6 +246,7 @@
(spec basic :overlay-at sprite)
(id uint32 :overlay-at sprite3d)))
;; definition of a launch group
(deftype sparticle-launch-group (basic)
((length int16)
(duration uint16)
@@ -91,10 +91,10 @@
;; note: these constants must match the sizes of the sprite arrays.
(define *sp-particle-system-2d*
(new 'global 'sparticle-system 1920 128 #f (-> *sprite-array-2d* vec-data) (-> *sprite-array-2d* adgif-data)))
(new 'global 'sparticle-system 1920 128 #f (the pointer (-> *sprite-array-2d* vec-data)) (-> *sprite-array-2d* adgif-data)))
(define *sp-particle-system-3d*
(new 'global 'sparticle-system 256 0 #t (-> *sprite-array-3d* vec-data) (-> *sprite-array-3d* adgif-data)))
(new 'global 'sparticle-system 256 0 #t (the pointer (-> *sprite-array-3d* vec-data)) (-> *sprite-array-3d* adgif-data)))
;;;;;;;;;;;;;;;;;;;;
;; alloc and block
+24 -11
View File
@@ -5,16 +5,24 @@
(#when PC_BIG_MEMORY
(defconstant SPRITE_MAX_AMOUNT_MULT 12))
;; sprite is the renderer for the particle system.
;; the vec-data types in this file are produced by the
;; particle system and then sent to the VU1 sprite renderer.
;; DECOMP BEGINS
;; Rendering mode for sprites
;; - use camera for sprites that are placed in the world
;; - use screen for sprites that are placed in screen pixel coordinates
(defenum sprite-matrix-mode
:type int32
(camera 0)
(screen 1))
;; Three quadwords uploaded per 2D sprite. The first holds position and x scale, the second carries
;; mode-specific flags or warp turns together with matrix, rotation, and y scale, and the third is
;; floating-point color.
;; data uploaded to the VU1 sprite renderer per sprite.
;; contains position, scale, color, and flags
;; the "2d" sprites always face the camera and rotation
;; controls their rotation along the camera view direction.
(deftype sprite-vec-data-2d (structure)
((x-y-z-sx vector :inline)
(flag-rot-sy vector :inline)
@@ -37,21 +45,24 @@
(data uint128 1 :overlay-at (-> x-y-z-sx quad))
(data64 uint64 6 :overlay-at (-> x-y-z-sx x))))
;; Two fixed-capacity sprite groups. num-valid is the active prefix of each group. The allocation
;; stores three vector quadwords followed by five adgif quadwords for every sprite.
;; Array of data uploaded to VU1 for 2d sprites
;; vec-data holds one sprite-vec-data-2d per sprite
;; adgif-data holds one adgif-shader (texture/blending settings) per sprite.
;; There are two groups: camera and screen.
(deftype sprite-array-2d (basic)
((num-sprites int32 2)
(num-valid int32 2)
(vec-data pointer)
(vec-data (inline-array sprite-vec-data-2d))
(adgif-data (inline-array adgif-shader))
(pad uint128 4)
(data uint128 1))
(:methods
(new (symbol type int int) _type_)))
;; Three quadwords uploaded per 3D sprite. Quaternion xyz is negated when the input w is negative,
;; selecting the equivalent quaternion with positive w so the omitted component can be reconstructed
;; from sqrt(1 - x*x - y*y - z*z). The second quadword's w lane remains the y scale.
;; data uploaded to the VU1 sprite renderer per sprite
;; contains position, scale, color, flags, and orientation.
;; orientation is a quaternion. By convention, sprite quaternions
;; always have +w, so the w can be recovered from sqrt(1 - x^2 - y^2 - z^2)
(deftype sprite-vec-data-3d (structure)
((x-y-z-sx vector :inline)
(qx-qy-qz-sy vector :inline)
@@ -73,11 +84,13 @@
(color rgbaf :inline :overlay-at (-> r-g-b-a x))
(data uint128 1 :overlay-at (-> x-y-z-sx quad))))
;; 3D sprites use the same two-group storage contract; the normal global array leaves group 1 empty.
;; Array of data uploaded to VU1 for 3d sprites.
;; There are two groups, but only the first is used.
;; (doing screen-space 3d sprites was never needed)
(deftype sprite-array-3d (basic)
((num-sprites int32 2)
(num-valid int32 2)
(vec-data pointer)
(vec-data (inline-array sprite-vec-data-3d))
(adgif-data (inline-array adgif-shader))
(data uint128 1))
(:methods
+2 -2
View File
@@ -409,7 +409,7 @@
(set! (-> result num-valid 0) 0)
(set! (-> result num-valid 1) 0)
;; internally, we put the vec-data and then the adgif-data
(set! (-> result vec-data) (-> result data))
(set! (-> result vec-data) (the (inline-array sprite-vec-data-2d) (-> result data)))
(set! (-> result adgif-data) (the-as (inline-array adgif-shader) (&-> result data vec-data-size)))
result))
@@ -429,7 +429,7 @@
(set! (-> result num-sprites 1) group-1-size)
(set! (-> result num-valid 0) 0)
(set! (-> result num-valid 1) 0)
(set! (-> result vec-data) (-> result data))
(set! (-> result vec-data) (the (inline-array sprite-vec-data-3d) (-> result data)))
(set! (-> result adgif-data) (the-as (inline-array adgif-shader) (&-> result data vec-data-size)))
result))
+1 -1
View File
@@ -250,7 +250,7 @@
(defpartgroup group-beach-waterfall
:id 162
:flags (always-draw unknown-bit-01)
:flags (always-draw randomize-order)
:bounds (static-bspherem 0 55 0 55)
:parts
((sp-item 677 :fade-after (meters 200) :falloff-to (meters 200))