forked from BradWBeer/clinch
-
Notifications
You must be signed in to change notification settings - Fork 0
/
buffer.lisp
179 lines (143 loc) · 5.55 KB
/
buffer.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
;;;; buffer.lisp
;;;; Please see the licence.txt for the CLinch
(in-package #:clinch)
(defun cffi-type->gl-type (type)
(case type
(:unsigned-char :unsigned-byte)
(otherwise type)))
(defclass buffer ()
((id
:reader id
:initform nil
:initarg :id)
(type
:accessor qtype
:initarg :qtype
:initform :float)
(usage
:accessor usage
:initform :static-draw
:initarg usage)
(stride
:reader Stride
:initform 3
:initarg :stride)
(Vertex-Count
:reader Vertex-Count
:initform nil
:initarg :count)
(target
:reader target
:initform :array-buffer
:initarg :target)
(loaded
:accessor loaded?
:initform nil))
(:documentation "Creates and keeps track of buffer object (shared memory with gpu, sort of). Base class of texture class."))
(defmethod initialize-instance :after ((this buffer) &key data)
"Sets up a buffer instance.
type: cffi type NOTE: use :unsigned-int if you are creating an index buffer.
id: OpenGL buffer id
vcount: vertex count (or number of tuples if not using vertexes)
stride: The number of items in each vertex (or each tuple.) NOTE: use 1 if you are creating an index buffer.
target: OpenGL buffer target. If you use this, think about subclassing. For more info lookup glBindBuffer().
NOTE: use :element-array-buffer if you are creating an index buffer.
usage: Tells OpenGL how often you wish to access the buffer.
loaded: Has data been put into the buffer. Buffers without data is just future storage, just be sure to set it before you use it."
(with-slots ((type type)
(id id)
(vcount vertex-count)
(target target)
(stride stride)
(usage usage)
(loaded? loaded)) this
;; if they didn't give a vcount, see if we can derive one...
(when (and (not vcount) (listp data))
(setf vcount (/ (length data) stride)))
(unless id
(setf id (car (gl:gen-buffers 1))))
(gl:bind-buffer target id)
(cond
;; Raw CFFI data?
((cffi:pointerp data)
(%gl:Buffer-Data target
(size-in-bytes this)
data
usage)
(setf loaded? t))
;; Data in List?
(data
(let ((p (cffi:foreign-alloc type :initial-contents data :count (get-size this))))
(unwind-protect
(progn (%gl:Buffer-Data target
(size-in-bytes this)
p
usage)
(setf loaded? t))
(cffi:foreign-free p))))
;; No Data?
(t
(%gl:Buffer-Data target
(size-in-bytes this)
(cffi:null-pointer)
usage)
(setf loaded? nil)))))
(defmethod bind ((this buffer) &key )
"Wrapper around glBindBuffer. Puts the buffer into play."
(gl:bind-buffer (target this) (id this)))
(defmethod get-size ((this buffer) &key)
"Calculates the number of VALUES (stride + vcount) this buffer contains."
(* (stride this) (vertex-count this)))
(defmethod size-in-bytes ((this buffer))
"Calculates how many bytes this buffer consists of."
(*
(get-size this)
(cffi:foreign-type-size (slot-value this 'type))))
(defmethod bind-buffer-to-vertex-array ((this buffer))
"Use buffer in shader for the vertex array: The built-in variable gl_Vertex."
(gl:Enable-Client-State :VERTEX-ARRAY)
(gl:bind-buffer (target this) (id this))
(%gl:vertex-pointer (stride this) (qtype this) 0 (cffi:null-pointer)))
(defmethod bind-buffer-to-normal-array ((this buffer))
"Use buffer in shader for the vertex array: The built-in variable gl_Vertex."
(gl:Enable-Client-State :NORMAL-ARRAY)
(gl:bind-buffer (target this) (id this))
(%gl:normal-pointer (qtype this) 0 (cffi:null-pointer)))
(defmethod bind-buffer-to-attribute-array ((this buffer) (shader shader) name)
"Bind buffer to a shader attribute."
(let ((id (cddr (get-attribute-id shader name))))
(gl:enable-vertex-attrib-array id)
(gl:bind-buffer (target this) (id this))
(gl:vertex-attrib-pointer id
(stride this)
(qtype this)
0 0 (cffi:null-pointer))))
(defmethod draw-with-index-buffer ((this buffer))
"Use this buffer as an index array and draw somthing."
(gl:bind-buffer (target this) (id this))
(%gl:draw-elements :triangles (Vertex-Count this)
(qtype this)
(cffi:null-pointer)))
(defmethod map-buffer ((this buffer) &optional (access :READ-WRITE))
"Returns a pointer to the buffer data. YOU MUST CALL UNMAP-BUFFER AFTER YOU ARE DONE!
Access options are: :Read-Only, :Write-Only, and :READ-WRITE. NOTE: Using :read-write is slower than the others. If you can, use them instead."
(gl:bind-buffer (target this) (id this))
(gl:map-buffer (target this) access))
(defmethod unmap-buffer ((this buffer))
"Release the pointer given by map-buffer. NOTE: THIS TAKES THE BUFFER OBJECT, NOT THE POINTER! ALSO, DON'T TRY TO RELASE THE POINTER."
(gl:unmap-buffer (target this))
(gl:bind-buffer (target this) 0))
(defmethod unload ((this buffer) &key)
"Release buffer resources."
(gl:delete-buffers (list (id this))))
(defmacro with-mapped-buffer ((name buffer &optional (access :READ-WRITE)) &body body)
"Convenience macro for mapping and unmapping the buffer data.
Name is the symbol name to use for the buffer pointer."
`(let ((,name (clinch::map-buffer ,buffer ,access)))
(unwind-protect
(progn ,@body)
(clinch::unmap-buffer ,buffer))))
(defmethod get-buffer-data ((this buffer))
(clinch:with-mapped-buffer (ptr this :read-only)
(loop for i from 0 to (1- (clinch:vertex-count this))
collect (cffi:mem-aref ptr (clinch:qtype this) i))))