a4c98f746db6a72198a78cb9fc4d71b9715fede4
[chickadee.git] / chickadee / render / framebuffer.scm
1 ;;; Chickadee Game Toolkit
2 ;;; Copyright © 2017 David Thompson <davet@gnu.org>
3 ;;;
4 ;;; Chickadee is free software: you can redistribute it and/or modify
5 ;;; it under the terms of the GNU General Public License as published
6 ;;; by the Free Software Foundation, either version 3 of the License,
7 ;;; or (at your option) any later version.
8 ;;;
9 ;;; Chickadee is distributed in the hope that it will be useful, but
10 ;;; WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ;;; General Public License for more details.
13 ;;;
14 ;;; You should have received a copy of the GNU General Public License
15 ;;; along with this program. If not, see
16 ;;; <http://www.gnu.org/licenses/>.
17
18 ;;; Commentary:
19 ;;
20 ;; Render to texture.
21 ;;
22 ;;; Code:
23
24 (define-module (chickadee render framebuffer)
25 #:use-module (oop goops)
26 #:use-module (ice-9 match)
27 #:use-module (srfi srfi-9)
28 #:use-module (system foreign)
29 #:use-module (gl)
30 #:use-module (gl enums)
31 #:use-module (chickadee render gl)
32 #:use-module (chickadee render gpu)
33 #:use-module ((chickadee render texture) #:select (make-texture null-texture))
34 #:use-module (chickadee render viewport)
35 #:export (make-framebuffer
36 framebuffer?
37 framebuffer-texture
38 framebuffer-viewport
39 null-framebuffer
40 apply-framebuffer
41 *framebuffer-state*))
42
43 (define (generate-framebuffer)
44 "Generate a new OpenGL framebuffer object."
45 (let ((bv (u32vector 1)))
46 (gl-gen-framebuffers 1 (bytevector->pointer bv))
47 (u32vector-ref bv 0)))
48
49 (define (generate-renderbuffer)
50 "Generate a new OpenGL renderbuffer object."
51 (let ((bv (u32vector 1)))
52 (gl-gen-renderbuffers 1 (bytevector->pointer bv))
53 (u32vector-ref bv 0)))
54
55 (define-record-type <framebuffer>
56 (%make-framebuffer id renderbuffer-id texture viewport)
57 framebuffer?
58 (id framebuffer-id)
59 (renderbuffer-id framebuffer-renderbuffer-id)
60 (texture framebuffer-texture)
61 (viewport framebuffer-viewport))
62
63 (define null-framebuffer
64 (%make-framebuffer 0 0 null-texture null-viewport))
65
66 (define <<framebuffer>> (class-of null-framebuffer))
67
68 (define (free-framebuffer framebuffer)
69 (gl-delete-renderbuffers 1
70 (bytevector->pointer
71 (u32vector
72 (framebuffer-renderbuffer-id framebuffer))))
73 (gl-delete-framebuffers 1
74 (bytevector->pointer
75 (u32vector
76 (framebuffer-id framebuffer)))))
77
78 (define-method (gpu-finalize (framebuffer <<framebuffer>>))
79 (free-framebuffer framebuffer))
80
81 (define (apply-framebuffer framebuffer)
82 (gl-bind-framebuffer (version-3-0 framebuffer)
83 (framebuffer-id framebuffer)))
84
85 (define *framebuffer-state*
86 (make-gpu-state apply-framebuffer null-framebuffer))
87
88 (define make-framebuffer
89 (let ((draw-buffers (u32vector (version-3-0 color-attachment0))))
90 (lambda* (width height #:key (min-filter 'linear) (mag-filter 'linear)
91 (wrap-s 'repeat) (wrap-t 'repeat))
92 "Create a new framebuffer that renders to a texture with
93 dimensions WIDTH x HEIGHT."
94 (let* ((framebuffer-id (generate-framebuffer))
95 (renderbuffer-id (generate-renderbuffer))
96 (texture (make-texture #f width height
97 #:flip? #t
98 #:min-filter min-filter
99 #:mag-filter mag-filter
100 #:wrap-s wrap-s
101 #:wrap-t wrap-t))
102 ;; It is convenient to make a default viewport for the
103 ;; framebuffer so that the rendering engine can set it
104 ;; whenever it changes to this framebuffer, saving users
105 ;; the trouble of having to this tedious task themselves.
106 (viewport (make-viewport 0 0 width height))
107 (framebuffer (%make-framebuffer framebuffer-id
108 renderbuffer-id
109 texture
110 viewport)))
111 (gpu-state-set! *framebuffer-state* framebuffer)
112 ;; Setup depth buffer.
113 (gl-bind-renderbuffer (version-3-0 renderbuffer)
114 renderbuffer-id)
115 (gl-renderbuffer-storage (version-3-0 renderbuffer)
116 (pixel-format depth-component)
117 width
118 height)
119 (gl-framebuffer-renderbuffer (version-3-0 framebuffer)
120 (arb-framebuffer-object depth-attachment)
121 (version-3-0 renderbuffer)
122 renderbuffer-id)
123 ;; Setup framebuffer.
124 (gl-framebuffer-texture-2d (version-3-0 framebuffer)
125 (version-3-0 color-attachment0)
126 (texture-target texture-2d)
127 ((@@ (chickadee render texture) texture-id)
128 texture)
129 0)
130 (gl-draw-buffers 1 (bytevector->pointer draw-buffers))
131 ;; Check for errors.
132 (unless (= (gl-check-framebuffer-status (version-3-0 framebuffer))
133 (version-3-0 framebuffer-complete))
134 (error "Framebuffer cannot be created"))
135 framebuffer))))