1 /******************************************************************************
2 Copyright (C) 2013 by Hugh Bailey <obs.jim@gmail.com>
3
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation, either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU 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 <http://www.gnu.org/licenses/>.
16 ******************************************************************************/
17
18 #include <graphics/vec3.h>
19 #include "gl-subsystem.h"
20
create_buffers(struct gs_vertex_buffer * vb)21 static bool create_buffers(struct gs_vertex_buffer *vb)
22 {
23 GLenum usage = vb->dynamic ? GL_STREAM_DRAW : GL_STATIC_DRAW;
24 size_t i;
25
26 if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->vertex_buffer,
27 vb->data->num * sizeof(struct vec3),
28 vb->data->points, usage))
29 return false;
30
31 if (vb->data->normals) {
32 if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->normal_buffer,
33 vb->data->num * sizeof(struct vec3),
34 vb->data->normals, usage))
35 return false;
36 }
37
38 if (vb->data->tangents) {
39 if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->tangent_buffer,
40 vb->data->num * sizeof(struct vec3),
41 vb->data->tangents, usage))
42 return false;
43 }
44
45 if (vb->data->colors) {
46 if (!gl_create_buffer(GL_ARRAY_BUFFER, &vb->color_buffer,
47 vb->data->num * sizeof(uint32_t),
48 vb->data->colors, usage))
49 return false;
50 }
51
52 da_reserve(vb->uv_buffers, vb->data->num_tex);
53 da_reserve(vb->uv_sizes, vb->data->num_tex);
54
55 for (i = 0; i < vb->data->num_tex; i++) {
56 GLuint tex_buffer;
57 struct gs_tvertarray *tv = vb->data->tvarray + i;
58 size_t size = vb->data->num * sizeof(float) * tv->width;
59
60 if (!gl_create_buffer(GL_ARRAY_BUFFER, &tex_buffer, size,
61 tv->array, usage))
62 return false;
63
64 da_push_back(vb->uv_buffers, &tex_buffer);
65 da_push_back(vb->uv_sizes, &tv->width);
66 }
67
68 if (!vb->dynamic) {
69 gs_vbdata_destroy(vb->data);
70 vb->data = NULL;
71 }
72
73 if (!gl_gen_vertex_arrays(1, &vb->vao))
74 return false;
75
76 return true;
77 }
78
device_vertexbuffer_create(gs_device_t * device,struct gs_vb_data * data,uint32_t flags)79 gs_vertbuffer_t *device_vertexbuffer_create(gs_device_t *device,
80 struct gs_vb_data *data,
81 uint32_t flags)
82 {
83 struct gs_vertex_buffer *vb = bzalloc(sizeof(struct gs_vertex_buffer));
84 vb->device = device;
85 vb->data = data;
86 vb->num = data->num;
87 vb->dynamic = flags & GS_DYNAMIC;
88
89 if (!create_buffers(vb)) {
90 blog(LOG_ERROR, "device_vertexbuffer_create (GL) failed");
91 gs_vertexbuffer_destroy(vb);
92 return NULL;
93 }
94
95 return vb;
96 }
97
gs_vertexbuffer_destroy(gs_vertbuffer_t * vb)98 void gs_vertexbuffer_destroy(gs_vertbuffer_t *vb)
99 {
100 if (vb) {
101 if (vb->vertex_buffer)
102 gl_delete_buffers(1, &vb->vertex_buffer);
103 if (vb->normal_buffer)
104 gl_delete_buffers(1, &vb->normal_buffer);
105 if (vb->tangent_buffer)
106 gl_delete_buffers(1, &vb->tangent_buffer);
107 if (vb->color_buffer)
108 gl_delete_buffers(1, &vb->color_buffer);
109 if (vb->uv_buffers.num)
110 gl_delete_buffers((GLsizei)vb->uv_buffers.num,
111 vb->uv_buffers.array);
112
113 if (vb->vao)
114 gl_delete_vertex_arrays(1, &vb->vao);
115
116 da_free(vb->uv_sizes);
117 da_free(vb->uv_buffers);
118 gs_vbdata_destroy(vb->data);
119
120 bfree(vb);
121 }
122 }
123
gs_vertexbuffer_flush_internal(gs_vertbuffer_t * vb,const struct gs_vb_data * data)124 static inline void gs_vertexbuffer_flush_internal(gs_vertbuffer_t *vb,
125 const struct gs_vb_data *data)
126 {
127 size_t i;
128 size_t num_tex = data->num_tex < vb->data->num_tex ? data->num_tex
129 : vb->data->num_tex;
130
131 if (!vb->dynamic) {
132 blog(LOG_ERROR, "vertex buffer is not dynamic");
133 goto failed;
134 }
135
136 if (data->points) {
137 if (!update_buffer(GL_ARRAY_BUFFER, vb->vertex_buffer,
138 data->points,
139 data->num * sizeof(struct vec3)))
140 goto failed;
141 }
142
143 if (vb->normal_buffer && data->normals) {
144 if (!update_buffer(GL_ARRAY_BUFFER, vb->normal_buffer,
145 data->normals,
146 data->num * sizeof(struct vec3)))
147 goto failed;
148 }
149
150 if (vb->tangent_buffer && data->tangents) {
151 if (!update_buffer(GL_ARRAY_BUFFER, vb->tangent_buffer,
152 data->tangents,
153 data->num * sizeof(struct vec3)))
154 goto failed;
155 }
156
157 if (vb->color_buffer && data->colors) {
158 if (!update_buffer(GL_ARRAY_BUFFER, vb->color_buffer,
159 data->colors, data->num * sizeof(uint32_t)))
160 goto failed;
161 }
162
163 for (i = 0; i < num_tex; i++) {
164 GLuint buffer = vb->uv_buffers.array[i];
165 struct gs_tvertarray *tv = data->tvarray + i;
166 size_t size = data->num * tv->width * sizeof(float);
167
168 if (!update_buffer(GL_ARRAY_BUFFER, buffer, tv->array, size))
169 goto failed;
170 }
171
172 return;
173
174 failed:
175 blog(LOG_ERROR, "gs_vertexbuffer_flush (GL) failed");
176 }
177
gs_vertexbuffer_flush(gs_vertbuffer_t * vb)178 void gs_vertexbuffer_flush(gs_vertbuffer_t *vb)
179 {
180 gs_vertexbuffer_flush_internal(vb, vb->data);
181 }
182
gs_vertexbuffer_flush_direct(gs_vertbuffer_t * vb,const struct gs_vb_data * data)183 void gs_vertexbuffer_flush_direct(gs_vertbuffer_t *vb,
184 const struct gs_vb_data *data)
185 {
186 gs_vertexbuffer_flush_internal(vb, data);
187 }
188
gs_vertexbuffer_get_data(const gs_vertbuffer_t * vb)189 struct gs_vb_data *gs_vertexbuffer_get_data(const gs_vertbuffer_t *vb)
190 {
191 return vb->data;
192 }
193
get_vb_buffer(struct gs_vertex_buffer * vb,enum attrib_type type,size_t index,GLint * width,GLenum * gl_type)194 static inline GLuint get_vb_buffer(struct gs_vertex_buffer *vb,
195 enum attrib_type type, size_t index,
196 GLint *width, GLenum *gl_type)
197 {
198 *gl_type = GL_FLOAT;
199 *width = 4;
200
201 if (type == ATTRIB_POSITION) {
202 return vb->vertex_buffer;
203 } else if (type == ATTRIB_NORMAL) {
204 return vb->normal_buffer;
205 } else if (type == ATTRIB_TANGENT) {
206 return vb->tangent_buffer;
207 } else if (type == ATTRIB_COLOR) {
208 *gl_type = GL_UNSIGNED_BYTE;
209 return vb->color_buffer;
210 } else if (type == ATTRIB_TEXCOORD) {
211 if (vb->uv_buffers.num <= index)
212 return 0;
213
214 *width = (GLint)vb->uv_sizes.array[index];
215 return vb->uv_buffers.array[index];
216 }
217
218 return 0;
219 }
220
load_vb_buffer(struct shader_attrib * attrib,struct gs_vertex_buffer * vb,GLint id)221 static bool load_vb_buffer(struct shader_attrib *attrib,
222 struct gs_vertex_buffer *vb, GLint id)
223 {
224 GLenum type;
225 GLint width;
226 GLuint buffer;
227 bool success = true;
228
229 buffer = get_vb_buffer(vb, attrib->type, attrib->index, &width, &type);
230 if (!buffer) {
231 blog(LOG_ERROR, "Vertex buffer does not have the required "
232 "inputs for vertex shader");
233 return false;
234 }
235
236 if (!gl_bind_buffer(GL_ARRAY_BUFFER, buffer))
237 return false;
238
239 glVertexAttribPointer(id, width, type, GL_TRUE, 0, 0);
240 if (!gl_success("glVertexAttribPointer"))
241 success = false;
242
243 glEnableVertexAttribArray(id);
244 if (!gl_success("glEnableVertexAttribArray"))
245 success = false;
246
247 if (!gl_bind_buffer(GL_ARRAY_BUFFER, 0))
248 success = false;
249
250 return success;
251 }
252
load_vb_buffers(struct gs_program * program,struct gs_vertex_buffer * vb,struct gs_index_buffer * ib)253 bool load_vb_buffers(struct gs_program *program, struct gs_vertex_buffer *vb,
254 struct gs_index_buffer *ib)
255 {
256 struct gs_shader *shader = program->vertex_shader;
257 size_t i;
258
259 if (!gl_bind_vertex_array(vb->vao))
260 return false;
261
262 for (i = 0; i < shader->attribs.num; i++) {
263 struct shader_attrib *attrib = shader->attribs.array + i;
264 if (!load_vb_buffer(attrib, vb, program->attribs.array[i]))
265 return false;
266 }
267
268 if (ib && !gl_bind_buffer(GL_ELEMENT_ARRAY_BUFFER, ib->buffer))
269 return false;
270
271 return true;
272 }
273
device_load_vertexbuffer(gs_device_t * device,gs_vertbuffer_t * vb)274 void device_load_vertexbuffer(gs_device_t *device, gs_vertbuffer_t *vb)
275 {
276 device->cur_vertex_buffer = vb;
277 }
278