;;-*-Lisp-*-
(in-package goal)

;; name: aligner-h.gc
;; name in dgo: aligner-h
;; dgos: GAME

;; +++align-opts
(defenum align-opts
  :bitfield #t
  :type uint32
  (adjust-x-vel)
  (adjust-y-vel)
  (adjust-xz-vel)
  (keep-other-velocities)
  (adjust-quat) ;; 16
  (alop0)
  (alop1)
  (alop2)
  (alop3)
  (alop4)
  (alop5)
  (no-gravity)
  (ignore-y-if-zero)
  )
;; ---align-opts


;; +++align-flags
(defenum align-flags
  :bitfield #t
  :type uint32
  (disabled) ;; keep object velocity
  )
;; ---align-flags


;; DECOMP BEGINS

(deftype align-control (basic)
  "Align-control is a utility for moving a process-drawable based on its animation.
The animation format has two special parent-like joints: prejoint and align.
The prejoint is the parent for all joints, so it causes all bones to move.
The align joint has no children, but the convention is that moving align will
cause the entire process-drawable's root to move, effectively moving the entire character.
Most of the time, this is the preferable way to move a character as part of an animation -
it will update their velocity and when the animation ends or is canceled,
the offset in position from playing the animation will stay. For example, if Jak punches,
his velocity will increase due to the animated align in the punch animation.
To implement this, the align-control computes the relative transform between align frames.
To apply the position offset, typically the velocity is updated, then the normal per-frame
physics update will end up moving the position. For orientation, there is no concept of
angular velocity, so instead align-control directly modifies the quaternion.
Unlike normal animation evaluation, the alignment's blend is computed in a different way
that doesn't blend and instead just picks the most recently pushed animation."
  ((flags        align-flags)
   (process      process-drawable)
   (frame-group  art-joint-anim)
   (frame-num    float)
   (matrix       matrix      2 :inline)
   (transform    transform   2 :inline)
   (delta        transformq  :inline)
   (last-speed   meters)
   (align        transformq  :inline :overlay-at (-> transform 0 trans data 0))
   )
  (:methods
    (new (symbol type process) _type_)
    (compute-delta-align! (_type_) transformq)
    (align! (_type_ align-opts float float float) trsqv)
    (adjust-root-no-gravity! (_type_ align-opts vector int float float) trsqv)
    (first-transform (_type_) transform)
    (second-transform (_type_) transform)
    )
  )


;; WARN: Return type mismatch object vs align-control.
(defmethod new align-control ((allocation symbol) (type-to-make type) (arg0 process))
  (let ((this (object-new allocation type-to-make (the-as int (-> type-to-make size)))))
    (when (zero? this)
      (go process-drawable-art-error "memory")
      (return (the-as align-control 0))
      )
    (set! (-> this process) (the-as process-drawable arg0))
    (the-as align-control this)
    )
  )
