-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathopengl-object.lisp
309 lines (258 loc) · 10.5 KB
/
opengl-object.lisp
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
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
;; opengl-object.lisp
;;
;; Copyright (c) 2022 Jeremiah LaRocco <[email protected]>
(in-package #:simple-gl)
(defclass opengl-object ()
((vao :initform 0
:type fixnum
:accessor vao
:documentation "The OpenGL VAO handle.")
(name :initform "GL Object"
:initarg :name
:type string
:documentation "The name of the object.")
(styles :initform (list (cons :point-style (point-style)))
:type (or null list)
:accessor styles
:initarg :styles
:documentation "A list of styles that apply to this object.")
(textures :initform nil
:type (or null list)
:accessor textures
:initarg :textures
:documentation "A list of textures used by this object.")
(buffers :initform nil
:type (or null list)
:accessor buffers
:initarg :buffers
:documentation "A list of buffers used by this object.")
(uniforms :initform nil
:type (or null list)
:accessor uniforms
:initarg :uniforms
:documentation "A list of uniforms used by this object.")
(primitive-type :initform :triangles
:documentation "OpenGL primitive type (:triangles, :points, :lines, etc.)"))
(:documentation "Base class for all objects that can be rendered in a scene."))
(defmethod initialized-p ((object opengl-object))
(not (zerop (vao object))))
(defun ensure-initialized (object)
(when (not (initialized-p object))
(initialize object)))
(defmethod show-info ((object opengl-object) &key (indent 0))
(let ((this-ws (indent-whitespace indent))
(plus-ws (indent-whitespace (+ 1 indent)))
(plus-plus-ws (indent-whitespace (+ 2 indent))))
(declare (ignorable plus-plus-ws plus-ws))
(format t "~aObject:~%" this-ws)
(show-slots plus-ws object '(name vao styles textures primitive-type))
(loop :for (name . style) :in (styles object) :do
(format t "~a~a~%" this-ws name)
(show-info style :indent (1+ indent)))
(loop :for (name . buffer) :in (buffers object) :do
(format t "~a~a~%" this-ws name)
(show-info buffer :indent (1+ indent)))
(loop :for (nil . uniform) :in (uniforms object) :do
(show-info uniform :indent (1+ indent)))))
(defmethod handle-key ((object opengl-object) window key scancode action mod-keys)
(declare (ignorable object window key scancode action mod-keys))
nil)
(defmethod handle-resize ((object opengl-object) window width height)
(declare (ignorable object window width height))
nil)
(defmethod handle-click ((object opengl-object) window click-info)
(declare (ignorable object window click-info))
nil)
(defmethod handle-scroll ((object opengl-object) window cpos x-scroll y-scroll)
(declare (ignorable object window cpos x-scroll y-scroll))
nil)
#+spacenav
(defmethod handle-3d-mouse-event ((object opengl-object) (event sn:motion-event))
(declare (ignorable object event))
(with-slots (uniforms buffers textures) object
(loop for buffer in buffers do
(handle-3d-mouse-event (cdr buffer) event))
(loop for texture in textures do
(handle-3d-mouse-event texture event))
(loop for uniform in uniforms do
(handle-3d-mouse-event (cdr uniform) event)))
nil)
(defmethod update ((object opengl-object) elapsed-seconds )
(declare (ignorable object elapsed-seconds))
(with-slots (textures styles buffers) object
(let ((buffers (concatenate
'list
(loop :for tex :in textures
:for updated = (update tex elapsed-seconds)
:when updated
:collect tex)
(loop :for (nil . style) :in styles
:for updated = (update style elapsed-seconds)
:when updated
:return style)
(loop :for (nil . buffer) :in buffers
:for updated = (update buffer elapsed-seconds)
:when updated
:collect buffer))))
(when buffers
(make-instance 'buffer-reloader
:buffers buffers)))))
(defun set-uniform (obj name value type &key (overwrite t))
(with-slots (uniforms) obj
(cond ((and overwrite
(assoc name uniforms :test #'string=))
(set-value (alexandria:assoc-value uniforms name :test #'string=) value type))
((null (assoc name uniforms :test #'string=))
(push (cons name (make-instance 'uniform :name name
:type type
:value value))
uniforms)))))
(defun get-uniform (obj name)
(with-slots (uniforms) obj
(if-let (previous (assoc name uniforms :test #'string=))
(cdr previous))))
(defmethod initialize :before ((object opengl-object) &key)
(cleanup object))
(defmethod initialize ((object opengl-object) &key)
(when (initialized-p object)
(error "initialize called on object where vao != 0 ~a" object))
(with-slots (vao styles initialized) object
(setf vao (gl:gen-vertex-array))
(gl:bind-vertex-array vao)
(loop :for (nil . style) :in styles :do
(build-style style))
(initialize-buffers object)
(initialize-uniforms object)
(initialize-textures object)))
(defmethod reload-buffers ((object opengl-object))
(with-slots (buffers) object
(dolist (buffer buffers)
(cleanup (cdr buffer)))
(setf buffers nil)
(initialize-buffers object)
t))
(defmethod rebuild-style ((object opengl-object))
(bind object)
(with-slots (styles buffers uniforms) object
(setf styles (loop
:for pair :in styles
:for (name . style) :in styles
:for new-style = (clone style)
:collect
(handler-case
(progn
(format t "Rebuilding style...")
(build-style new-style)
(format t "~%cleaning up~%")
(cleanup style)
(use-style new-style)
(cons name new-style))
(shader-error (condition)
(format t "Shader error: ~a~%" condition)
(format t "Not replacing style.~%")
pair))))
(loop
:for (nil . style) :in styles
:for program = (program style) :do
(use-style style)
(loop :for (nil . buffer) :in buffers :do
(bind buffer)
(associate-attributes buffer (program style)))
(loop :for (nil . uniform) :in uniforms :do
(use-uniform uniform program))))
t)
(defmethod needs-rebuild ((object opengl-object))
(with-slots (styles) object
(loop :for (nil . style) :in styles
:when (needs-rebuild style)
:collect style)))
(defmethod refill-textures ((object opengl-object))
(bind object)
(with-slots (textures buffers uniforms) object
(loop :for texture :in textures :do
(reload texture)))
t)
(defmethod initialize-uniforms ((object opengl-object) &key)
(set-uniform object "obj_transform" (meye 4) :mat4)
(set-uniform object "view_transform" (meye 4) :mat4)
t)
(defmethod initialize-buffers ((object opengl-object) &key)
(when (buffers object)
(error "Object buffers already setup!"))
(set-buffer object :vertices
(constant-attribute-buffer
(list
(vec3 -1.0f0 -1.0f0 0.0f0)
(vec4 0.1f0 0.8f0 0.1f0 1.0f0)
(vec3 1.0f0 -1.0f0 0.0f0)
(vec4 0.1f0 0.8f0 0.1f0 1.0f0)
(vec3 0.0f0 1.0f0 0.0f0)
(vec4 0.1f0 0.8f0 0.1f0 1.0f0))
(* 7 3)
'(("in_position" . :vec3) ("in_color" . :vec4))))
(set-buffer object
:indices
(constant-index-buffer 3)))
(defmethod initialize-textures ((object opengl-object) &key)
(declare (ignorable object))
(loop
:for texture :in (textures object)
:do
(initialize texture)))
(defmethod cleanup ((object opengl-object))
(with-slots (vao buffers textures uniforms styles) object
(when (/= 0 vao)
(gl:bind-vertex-array vao)
(dolist (texture textures)
(cleanup texture))
(dolist (uniform uniforms)
(cleanup (cdr uniform)))
(dolist (buffer buffers)
(cleanup (cdr buffer)))
(dolist (style styles)
(cleanup (cdr style)))
(gl:bind-vertex-array 0)
(gl:delete-vertex-arrays (list vao))
(setf buffers nil)
(setf vao 0))))
(defmethod bind ((object opengl-object))
(with-slots (vao buffers textures) object
(declare (type fixnum vao))
(when (zerop vao)
(error "Trying to bind an uninitialized opengl-object!"))
(gl:bind-vertex-array vao)))
(defmethod render ((object opengl-object))
(with-slots (buffers uniforms primitive-type styles) object
(bind object)
(loop :for (nil . style) :in styles :do
(use-style style)
(loop :for (nil . uniform) :in uniforms :do
(use-uniform uniform (program style)))
(when (and (assoc-value buffers :vertices)
(assoc-value buffers :indices))
(gl:draw-elements primitive-type
(gl:make-null-gl-array :unsigned-int)
:count (idx-count (assoc-value buffers :indices)))))))
(defun set-buffer (object buffer-name buffer)
(declare (type opengl-object object)
(type buffer buffer))
(with-slots (buffers styles idx-count) object
(if-let ((location (assoc buffer-name buffers)))
(progn
(cleanup (cdr location))
(rplacd location buffer))
(push (cons buffer-name buffer) buffers))
(bind buffer)
(loop :for (nil . style) :in styles :do
(associate-attributes buffer (program style)))))
(defun get-buffer (object buffer-name)
(assoc-value (buffers object) buffer-name))
(defun add-style (object name new-style)
(declare (type opengl-object object))
(with-slots (styles) object
(when (null (assoc name styles))
(push (cons name new-style) styles))))
(defun add-texture (object texture)
(declare (type opengl-object object)
(type texture texture))
(push texture (textures object)))