render: framebuffer: Add default projection matrix for convenience.
[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 math matrix)
32 #:use-module (chickadee render gl)
33 #:use-module (chickadee render gpu)
34 #:use-module ((chickadee render texture) #:select (make-texture null-texture))
35 #:use-module (chickadee render viewport)
36 #:export (make-framebuffer
37 framebuffer?
38 framebuffer-texture
39 framebuffer-viewport
40 framebuffer-projection
41 null-framebuffer
42 apply-framebuffer
43 *framebuffer-state*))
44
45 (define (generate-framebuffer)
46 "Generate a new OpenGL framebuffer object."
47 (let ((bv (u32vector 1)))
48 (gl-gen-framebuffers 1 (bytevector->pointer bv))
49 (u32vector-ref bv 0)))
50
51 (define (generate-renderbuffer)
52 "Generate a new OpenGL renderbuffer object."
53 (let ((bv (u32vector 1)))
54 (gl-gen-renderbuffers 1 (bytevector->pointer bv))
55 (u32vector-ref bv 0)))
56
57 (define-record-type <framebuffer>
58 (%make-framebuffer id renderbuffer-id texture viewport projection)
59 framebuffer?
60 (id framebuffer-id)
61 (renderbuffer-id framebuffer-renderbuffer-id)
62 (texture framebuffer-texture)
63 (viewport framebuffer-viewport)
64 (projection framebuffer-projection))
65
66 (define null-framebuffer
67 (%make-framebuffer 0 0 null-texture null-viewport (make-identity-matrix4)))
68
69 (define <<framebuffer>> (class-of null-framebuffer))
70
71 (define (free-framebuffer framebuffer)
72 (gl-delete-renderbuffers 1
73 (bytevector->pointer
74 (u32vector
75 (framebuffer-renderbuffer-id framebuffer))))
76 (gl-delete-framebuffers 1
77 (bytevector->pointer
78 (u32vector
79 (framebuffer-id framebuffer)))))
80
81 (define-method (gpu-finalize (framebuffer <<framebuffer>>))
82 (free-framebuffer framebuffer))
83
84 (define (apply-framebuffer framebuffer)
85 (gl-bind-framebuffer (version-3-0 framebuffer)
86 (framebuffer-id framebuffer)))
87
88 (define *framebuffer-state*
89 (make-gpu-state apply-framebuffer null-framebuffer))
90
91 (define make-framebuffer
92 (let ((draw-buffers (u32vector (version-3-0 color-attachment0))))
93 (lambda* (width height #:key (min-filter 'linear) (mag-filter 'linear)
94 (wrap-s 'repeat) (wrap-t 'repeat))
95 "Create a new framebuffer that renders to a texture with
96 dimensions WIDTH x HEIGHT."
97 (let* ((framebuffer-id (generate-framebuffer))
98 (renderbuffer-id (generate-renderbuffer))
99 (texture (make-texture #f width height
100 #:flip? #t
101 #:min-filter min-filter
102 #:mag-filter mag-filter
103 #:wrap-s wrap-s
104 #:wrap-t wrap-t))
105 ;; It is convenient to make a default viewport and
106 ;; projection matrix for the framebuffer so that the
107 ;; rendering engine can set it whenever it changes to
108 ;; this framebuffer, saving users the trouble of having
109 ;; to this tedious task themselves.
110 (viewport (make-viewport 0 0 width height))
111 (projection (orthographic-projection 0 width height 0 0 1))
112 (framebuffer (%make-framebuffer framebuffer-id
113 renderbuffer-id
114 texture
115 viewport
116 projection)))
117 (gpu-state-set! *framebuffer-state* framebuffer)
118 ;; Setup depth buffer.
119 (gl-bind-renderbuffer (version-3-0 renderbuffer)
120 renderbuffer-id)
121 (gl-renderbuffer-storage (version-3-0 renderbuffer)
122 (pixel-format depth-component)
123 width
124 height)
125 (gl-framebuffer-renderbuffer (version-3-0 framebuffer)
126 (arb-framebuffer-object depth-attachment)
127 (version-3-0 renderbuffer)
128 renderbuffer-id)
129 ;; Setup framebuffer.
130 (gl-framebuffer-texture-2d (version-3-0 framebuffer)
131 (version-3-0 color-attachment0)
132 (texture-target texture-2d)
133 ((@@ (chickadee render texture) texture-id)
134 texture)
135 0)
136 (gl-draw-buffers 1 (bytevector->pointer draw-buffers))
137 ;; Check for errors.
138 (unless (= (gl-check-framebuffer-status (version-3-0 framebuffer))
139 (version-3-0 framebuffer-complete))
140 (error "Framebuffer cannot be created"))
141 framebuffer))))