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