;;; Copyright (C) 2024 David Thompson <dave@spritely.institute>
;;;
;;; Licensed under the Apache License, Version 2.0 (the "License");
;;; you may not use this file except in compliance with the License.
;;; You may obtain a copy of the License at
;;;
;;;    http://www.apache.org/licenses/LICENSE-2.0
;;;
;;; Unless required by applicable law or agreed to in writing, software
;;; distributed under the License is distributed on an "AS IS" BASIS,
;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;;; See the License for the specific language governing permissions and
;;; limitations under the License.

(define-module (game effects)
  #:use-module (dom canvas)
  #:use-module (game scripts)
  #:use-module (game time)
  #:use-module (ice-9 match)
  #:use-module (math)
  #:use-module (srfi srfi-9)
  #:use-module (scheme time)
  #:export (ease:smoothstep
            ease:linear

            make-effect
            effect?
            effect-started?
            effect-type
            effect-duration
            effect-start!
            draw-effect

            make-fade-out+in-effect
            make-screen-shake-effect
            make-wipe-effect))

(define (ease:smoothstep t)
  (* t t (- 3 (* 2 t))))

(define (ease:linear t) t)

(define-record-type <effect>
  (%make-effect type draw ease duration start)
  effect?
  (type effect-type)
  (draw effect-draw)
  (ease effect-ease)
  (duration effect-duration)
  (start effect-start set-effect-start!))

(define* (make-effect type duration draw #:optional (ease ease:smoothstep))
  (%make-effect type draw ease duration #f))

(define (effect-started? effect)
  (number? (effect-start effect)))

(define (effect-start! effect)
  (set-effect-start! effect (current-time*)))

(define (draw-effect context effect)
  (match effect
    (($ <effect> type draw ease duration start)
     (when (number? start)
       (let ((dt (- (current-time*) start)))
         (if (>= dt duration)
             (set-effect-start! effect #f)
             (let ((t (ease (/ dt duration))))
               (draw context t))))))))

;; Duplicated from game.scm but gotta go fast!!
(define game-width 320.0)
(define game-height 240.0)

;; on-transition is a last-minute hack to make it possible to sync the
;; loading of the next level with the moment when the screen is
;; completely black.
(define (make-fade-out+in-effect duration on-transition)
  (define transitioned? #f)
  (define (maybe-transition)
    (unless transitioned?
      (set! transitioned? #t)
      (on-transition)))
  (define (draw context t)
    (if (< t 0.5)
        (set-global-alpha! context (* t 2.0))
        (begin
          (maybe-transition)
          (set-global-alpha! context (- 1.0 (* (- t 0.5) 2.0)))))
    (set-fill-color! context "#000000")
    (fill-rect context 0.0 0.0 game-width game-height)
    (set-global-alpha! context 1.0))
  (make-effect 'post duration draw))

(define (make-screen-shake-effect duration)
  (define (draw context t)
    (let ((x (round (random)))
          (y (round (random))))
      (translate! context x y)))
  (make-effect 'pre duration draw))

(define (make-wipe-effect duration)
  (define (draw context t)
    (set-fill-color! context "#222034")
    (fill-rect context 0.0 0.0 (* game-width (- 1.0 t)) game-height))
  (make-effect 'post duration draw))