summaryrefslogtreecommitdiff
path: root/chickadee/graphics/stencil.scm
blob: e19307b6e838939faabd986acee68d8e619338c0 (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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
;;; Chickadee Game Toolkit
;;; Copyright © 2020, 2021 David Thompson <davet@gnu.org>
;;;
;;; Chickadee is free software: you can redistribute it and/or modify
;;; it under the terms of the GNU General Public License as published
;;; by the Free Software Foundation, either version 3 of the License,
;;; or (at your option) any later version.
;;;
;;; Chickadee is distributed in the hope that it will be useful, but
;;; WITHOUT ANY WARRANTY; without even the implied warranty of
;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
;;; General Public License for more details.
;;;
;;; You should have received a copy of the GNU General Public License
;;; along with this program.  If not, see
;;; <http://www.gnu.org/licenses/>.

(define-module (chickadee graphics stencil)
  #:use-module (ice-9 match)
  #:use-module (gl)
  #:use-module (chickadee graphics engine)
  #:use-module (chickadee graphics gl)
  #:use-module (srfi srfi-9)
  #:export (make-stencil-test
            stencil-test?
            stencil-test-mask-front
            stencil-test-mask-back
            stencil-test-function-front
            stencil-test-function-back
            stencil-test-function-mask-front
            stencil-test-function-mask-back
            stencil-test-reference-front
            stencil-test-reference-back
            stencil-test-on-fail-front
            stencil-test-on-fail-back
            stencil-test-on-depth-fail-front
            stencil-test-on-depth-fail-back
            stencil-test-on-pass-front
            stencil-test-on-pass-back
            default-stencil-test
            current-stencil-test))

(define-record-type <stencil-test>
  (%make-stencil-test mask-front mask-back function-front function-back
                      function-mask-front function-mask-back
                      reference-front reference-back
                      on-fail-front on-fail-back
                      on-depth-fail-front on-depth-fail-back
                      on-pass-front on-pass-back)
  stencil-test?
  (mask-front stencil-test-mask-front)
  (mask-back stencil-test-mask-back)
  (function-front stencil-test-function-front)
  (function-back stencil-test-function-back)
  (function-mask-front stencil-test-function-mask-front)
  (function-mask-back stencil-test-function-mask-back)
  (reference-front stencil-test-reference-front)
  (reference-back stencil-test-reference-back)
  (on-fail-front stencil-test-on-fail-front)
  (on-fail-back stencil-test-on-fail-back)
  (on-depth-fail-front stencil-test-on-depth-fail-front)
  (on-depth-fail-back stencil-test-on-depth-fail-back)
  (on-pass-front stencil-test-on-pass-front)
  (on-pass-back stencil-test-on-pass-back))

(define* (make-stencil-test #:key (mask #xFF) (function 'always)
                            (function-mask #xFF) (reference 0)
                            (on-fail 'keep) (on-depth-fail 'keep) (on-pass 'keep)
                            (mask-front mask) (mask-back mask)
                            (function-front function) (function-back function)
                            (function-mask-front function-mask)
                            (function-mask-back function-mask)
                            (reference-front reference)
                            (reference-back reference)
                            (on-fail-front on-fail) (on-fail-back on-fail)
                            (on-depth-fail-front on-depth-fail)
                            (on-depth-fail-back on-depth-fail)
                            (on-pass-front on-pass) (on-pass-back on-pass))
  (%make-stencil-test mask-front mask-back function-front function-back
                      function-mask-front function-mask-back
                      reference-front reference-back
                      on-fail-front on-fail-back
                      on-depth-fail-front on-depth-fail-back
                      on-pass-front on-pass-back))

(define default-stencil-test (make-stencil-test))

(define* (bind-stencil-test stencil)
  (define (symbol->op sym)
    (match sym
      ('zero (stencil-op zero))
      ('keep (stencil-op keep))
      ('replace (stencil-op replace))
      ('increment (stencil-op incr))
      ('increment-wrap (version-1-4 incr-wrap))
      ('decrement (stencil-op decr))
      ('decrement-wrap (version-1-4 decr-wrap))
      ('invert (stencil-op invert))))
  (define (symbol->function sym)
    (match sym
      ('always (stencil-function always))
      ('never (stencil-function never))
      ('less-than (stencil-function less))
      ('equal (stencil-function equal))
      ('less-than-or-equal (stencil-function lequal))
      ('greater-than (stencil-function greater))
      ('greater-than-or-equal (stencil-function gequal))
      ('not-equal (stencil-function notequal))))
  (if stencil
      (begin
        (gl-enable (enable-cap stencil-test))
        ;; Mask
        (gl-stencil-mask-separate (cull-face-mode front)
                                  (stencil-test-mask-front stencil))
        (gl-stencil-mask-separate (cull-face-mode back)
                                  (stencil-test-mask-back stencil))
        ;; Function
        (gl-stencil-func-separate (cull-face-mode front)
                                  (symbol->function
                                   (stencil-test-function-front stencil))
                                  (stencil-test-reference-front stencil)
                                  (stencil-test-function-mask-front stencil))
        (gl-stencil-func-separate (cull-face-mode back)
                                  (symbol->function
                                   (stencil-test-function-back stencil))
                                  (stencil-test-reference-back stencil)
                                  (stencil-test-function-mask-back stencil))
        ;; Operation
        (gl-stencil-op-separate (cull-face-mode front)
                                (symbol->op (stencil-test-on-fail-front stencil))
                                (symbol->op (stencil-test-on-depth-fail-front stencil))
                                (symbol->op (stencil-test-on-pass-front stencil)))
        (gl-stencil-op-separate (cull-face-mode back)
                                (symbol->op (stencil-test-on-fail-back stencil))
                                (symbol->op (stencil-test-on-depth-fail-back stencil))
                                (symbol->op (stencil-test-on-pass-back stencil))))
      (gl-disable (enable-cap stencil-test))))

(define-graphics-state stencil-test
  current-stencil-test
  #:default default-stencil-test
  #:bind bind-stencil-test)