summaryrefslogtreecommitdiff
path: root/catbird/region.scm
blob: 4ae4bc9e6afd6091f9ae418b0e7d70cae020e94b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
(define-module (catbird region)
  #:use-module (catbird camera)
  #:use-module (catbird config)
  #:use-module (catbird mixins)
  #:use-module (catbird node)
  #:use-module (catbird scene)
  #:use-module (chickadee)
  #:use-module (chickadee data array-list)
  #:use-module (chickadee graphics engine)
  #:use-module (chickadee graphics viewport)
  #:use-module (chickadee math rect)
  #:use-module (ice-9 exceptions)
  #:use-module (oop goops)
  #:export (<region>
            make-region
            area
            area-x
            area-y
            area-width
            area-height
            camera
            scene
            replace-scene
            push-scene
            pop-scene)
  #:re-export (name
               rank
               render
               update))

(define-root-class <region> (<renderable> <updatable> <nameable> <rankable>)
  (area #:accessor area #:init-keyword #:area)
  (camera #:accessor camera #:init-keyword #:camera #:init-value #f)
  (scene #:accessor scene #:init-keyword #:scene #:init-value #f)
  (scene-stack #:getter scene-stack #:init-thunk make-array-list)
  (viewport #:accessor viewport))

(define-method (area-x (region <region>))
  (rect-x (area region)))

(define-method (area-y (region <region>))
  (rect-y (area region)))

(define-method (area-width (region <region>))
  (rect-width (area region)))

(define-method (area-height (region <region>))
  (rect-height (area region)))

(define (float->int x)
  (inexact->exact (round x)))

(define-method (initialize (region <region>) args)
  (next-method)
  (let ((r (area region)))
    (set! (viewport region)
          (make-viewport (float->int (rect-x r))
                         (float->int (rect-y r))
                         (float->int (rect-width r))
                         (float->int (rect-height r))))))

(define (make-region area name rank)
  (let* ((window (current-window))
         (w (window-width window))
         (h (window-height window)))
    (when (or (< (rect-left area) 0.0)
              (< (rect-bottom area) 0.0)
              (> (rect-right area) w)
              (> (rect-top area) h))
      (raise-exception
       (make-exception-with-message "region area exceeds window area")))
    (make <region> #:area area #:name name #:rank rank)))

(define-method (replace-scene (r <region>) (new-scene <scene>))
  (let ((old-scene (scene r)))
    (when old-scene (on-exit old-scene))
    (set! (scene r) new-scene)
    (set! (regions new-scene) (cons r (regions new-scene)))
    (on-enter new-scene)))

(define-method (push-scene (region <region>) (new-scene <scene>))
  (let ((old-scene (scene region)))
    (when old-scene
      (array-list-push! (scene-stack region) old-scene))
    (replace-scene region new-scene)))

(define-method (pop-scene (region <region>))
  (let ((stack (scene-stack region)))
    (unless (array-list-empty? stack)
      (replace-scene (array-list-pop! stack)))))

(define-method (update (region <region>) dt)
  (let ((s (scene region)))
    (when s (update/around s dt))))

(define-method (render (region <region>) alpha)
  (let ((s (scene region))
        (c (camera region)))
    (when (and s c)
      (parameterize ((current-camera c))
        (with-projection (projection-matrix (camera region))
          (render/around s alpha))))))