;; Film grain effect using xector operations
;; Demonstrates random xectors and mixing scalar/xector math

(require-primitives "xector")

(define-effect xector_grain
  :params (
    (intensity :type float :default 0.2 :range [0 1] :desc "Grain intensity")
    (colored :type bool :default false :desc "Use colored grain")
  )
  (let* (
         ;; Extract channels
         (r (red frame))
         (g (green frame))
         (b (blue frame))

         ;; Generate noise xector(s)
         ;; randn-x generates normal distribution noise
         (grain-amount (* intensity 50)))

    (if colored
        ;; Colored grain: different noise per channel
        (let* ((nr (randn-x frame 0 grain-amount))
               (ng (randn-x frame 0 grain-amount))
               (nb (randn-x frame 0 grain-amount)))
          (rgb (αclamp (α+ r nr) 0 255)
               (αclamp (α+ g ng) 0 255)
               (αclamp (α+ b nb) 0 255)))

        ;; Monochrome grain: same noise for all channels
        (let ((n (randn-x frame 0 grain-amount)))
          (rgb (αclamp (α+ r n) 0 255)
               (αclamp (α+ g n) 0 255)
               (αclamp (α+ b n) 0 255))))))
