summaryrefslogtreecommitdiff
path: root/sly/render.scm
blob: 6ff7bb9d4daf164a95ce65da14cdaae9db17b57a (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
;;; Sly
;;; Copyright (C) 2014 David Thompson <davet@gnu.org>
;;;
;;; Sly 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.
;;;
;;; Sly 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/>.

;;; Commentary:
;;
;; Manages the OpenGL state machine.
;;
;;; Code:

(define-module (sly render)
  #:use-module (rnrs bytevectors)
  #:use-module (ice-9 match)
  #:use-module (ice-9 q)
  #:use-module (srfi srfi-9)
  #:use-module (srfi srfi-42)
  #:use-module (gl)
  #:use-module (gl enums)
  #:use-module (gl low-level)
  #:use-module (sly wrappers gl)
  #:use-module (sly math transform)
  #:use-module (sly render shader)
  #:use-module (sly render texture)
  #:use-module (sly render utils)
  #:use-module (sly render mesh)
  #:use-module (sly render framebuffer)
  #:use-module (sly render camera)
  #:export (make-graphics
            graphics?
            graphics-blend-mode
            set-graphics-blend-mode!
            graphics-depth-test?
            set-graphics-depth-test!
            graphics-texture
            set-graphics-texture!
            graphics-shader
            set-graphics-shader!
            graphics-mesh
            set-graphics-mesh!
            graphics-framebuffer
            set-graphics-framebuffer!
            graphics-viewport
            set-graphics-viewport!
            graphics-model-view-transform
            graphics-model-view-mul!
            graphics-model-view-identity!
            with-model-view-excursion
            graphics-projection-transform
            graphics-projection-mul!
            graphics-projection-identity!
            with-projection-excursion
            with-graphics
            with-graphics-excursion))

;;;
;;; Transformation matrix stack.
;;;

(define (make-null-transform)
  (make-transform 0 0 0 0
                  0 0 0 0
                  0 0 0 0
                  0 0 0 0))

(define (make-transform-stack size)
  (let ((stack (make-q)))
    (do-ec (: i size) (q-push! stack (make-null-transform)))
    stack))

(define (copy-transform! src dest)
  (bytevector-copy! (transform-matrix src) 0
                    (transform-matrix dest) 0
                    64))

(define (call-with-transform-excursion stack thunk)
  (let ((t (q-pop! stack)))
    (dynamic-wind
      (const #t)
      (lambda ()
        (copy-transform! t (q-front stack))
        (thunk))
      (lambda ()
        (q-push! stack t)))))

(define (stack-transform-mul! stack t)
  (let ((dest (q-front stack)))
    (call-with-transform-excursion stack
      (lambda ()
        (transform*! dest (q-front stack) t)))))

(define (stack-transform-identity! stack)
  (copy-transform! identity-transform (q-front stack)))

;;;
;;; Graphics context.
;;;

(define-record-type <graphics>
  (%make-graphics blend-mode depth-test? texture shader
                  mesh framebuffer viewport projection model-view)
  graphics?
  (blend-mode graphics-blend-mode %set-graphics-blend-mode!)
  (depth-test? graphics-depth-test? %set-graphics-depth-test!)
  (texture graphics-texture %set-graphics-texture!)
  (shader graphics-shader %set-graphics-shader!)
  (mesh graphics-mesh %set-graphics-mesh!)
  (framebuffer graphics-framebuffer %set-graphics-framebuffer!)
  (viewport graphics-viewport %set-graphics-viewport!)
  (projection graphics-projection)
  (model-view graphics-model-view))

(define (make-context-switcher getter setter switch)
  (lambda* (gfx x #:optional force)
    (when (or force (not (equal? (getter gfx) x)))
      (setter gfx x)
      (switch x))))

(define set-graphics-blend-mode!
  (make-context-switcher graphics-blend-mode
                         %set-graphics-blend-mode!
                         apply-blend-mode))

(define set-graphics-depth-test!
  (make-context-switcher graphics-depth-test?
                         %set-graphics-depth-test!
                         apply-depth-test))

(define set-graphics-texture!
  (make-context-switcher graphics-texture
                         %set-graphics-texture!
                         apply-texture))

(define set-graphics-shader!
  (make-context-switcher graphics-shader
                         %set-graphics-shader!
                         apply-shader-program))

(define set-graphics-mesh!
  (make-context-switcher graphics-mesh
                         %set-graphics-mesh!
                         apply-mesh))

(define set-graphics-framebuffer!
  (make-context-switcher graphics-framebuffer
                         %set-graphics-framebuffer!
                         apply-framebuffer))

(define set-graphics-viewport!
  (make-context-switcher graphics-viewport
                         %set-graphics-viewport!
                         apply-viewport))

(define* (make-graphics #:optional (transform-stack-size 32))
  (%make-graphics #f #f #f #f #f #f #f
                  (make-transform-stack transform-stack-size)
                  (make-transform-stack transform-stack-size)))

(define (graphics-reset! gfx)
  (set-graphics-blend-mode!  gfx #f #t)
  (set-graphics-depth-test!  gfx #f #t)
  (set-graphics-texture!     gfx null-texture #t)
  (set-graphics-shader!      gfx null-shader-program #t)
  (set-graphics-mesh!        gfx null-mesh #t)
  (set-graphics-framebuffer! gfx null-framebuffer #t)
  (set-graphics-viewport!    gfx null-viewport #t)
  (stack-transform-identity! (graphics-projection gfx))
  (stack-transform-identity! (graphics-model-view gfx)))

(define-syntax-rule (with-graphics gfx body ...)
  (begin
    (graphics-reset! gfx)
    body ...
    (graphics-reset! gfx)))

(define (graphics-model-view-transform gfx)
  (q-front (graphics-model-view gfx)))

(define (graphics-model-view-mul! gfx t)
  (stack-transform-mul! (graphics-model-view gfx) t))

(define (graphics-model-view-identity! gfx)
  (stack-transform-identity! (graphics-model-view gfx)))

;; emacs: (put 'with-model-view-excursion 'scheme-indent-function 1)
(define-syntax-rule (with-model-view-excursion gfx body ...)
  (call-with-transform-excursion (graphics-model-view gfx)
    (lambda () body ...)))

(define (graphics-projection-transform gfx)
  (q-front (graphics-projection gfx)))

(define (graphics-projection-mul! gfx t)
  (stack-transform-mul! (graphics-projection gfx) t))

(define (graphics-projection-identity! gfx)
  (stack-transform-identity! (graphics-projection gfx)))

;; emacs: (put 'with-projection-excursion 'scheme-indent-function 1)
(define-syntax-rule (with-projection-excursion gfx body ...)
  (call-with-transform-excursion (graphics-projection gfx)
    (lambda () body ...)))

(define-syntax-rule (with-graphics-excursion gfx body ...)
  (match gfx
    (($ <graphics> blend-mode depth-test? texture shader mesh
        viewport framebuffer _ _)
     body ...
     (set-graphics-blend-mode!  gfx blend-mode)
     (set-graphics-depth-test!  gfx depth-test?)
     (set-graphics-texture!     gfx texture)
     (set-graphics-shader!      gfx shader)
     (set-graphics-mesh!        gfx mesh)
     (set-graphics-framebuffer! gfx framebuffer)
     (set-graphics-viewport!    gfx viewport))))