…aaand add PREFIX to the freebsd makefile too
[voxelands-alt.git] / src / graphics / mesh.c
blobc5e1d0506e364258f0fe9db5f828302ac19e06ac
1 /************************************************************************
2 * mesh.c
3 * voxelands - 3d voxel world sandbox game
4 * Copyright (C) Lisa 'darkrose' Milne 2016 <lisa@ltmnet.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14 * See the GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>
18 ************************************************************************/
20 #include "common.h"
21 #include "graphics.h"
22 #include "array.h"
24 #include <string.h>
26 /* create a new mesh */
27 mesh_t *mesh_create(GLenum mode)
29 mesh_t *m = malloc(sizeof(mesh_t));
30 m->mode = mode;
31 m->mat = NULL;
32 m->col = NULL;
33 m->v = array_create(ARRAY_TYPE_FLOAT);
34 m->n = NULL;
35 m->t = NULL;
36 m->i = array_create(ARRAY_TYPE_INT);
37 m->w = NULL;
38 m->m = NULL;
40 m->option = 0;
42 m->vao.state = 0;
44 m->bounds.max.x = 0.0;
45 m->bounds.max.y = 0.0;
46 m->bounds.max.z = 0.0;
47 m->bounds.min.x = 0.0;
48 m->bounds.min.y = 0.0;
49 m->bounds.min.z = 0.0;
51 return m;
54 /* destroy a mesh */
55 void mesh_free(mesh_t *m)
57 if (m->col)
58 free(m->col);
59 if (m->v)
60 array_free(m->v,1);
61 if (m->n)
62 array_free(m->n,1);
63 if (m->t)
64 array_free(m->t,1);
65 if (m->i)
66 array_free(m->i,1);
67 if (m->w)
68 array_free(m->w,1);
70 if (m->vao.state) {
71 if (m->vao.vertices)
72 glDeleteBuffers(1,&m->vao.vertices);
73 if (m->vao.normals)
74 glDeleteBuffers(1,&m->vao.normals);
75 if (m->vao.texcoords)
76 glDeleteBuffers(1,&m->vao.texcoords);
77 if (m->vao.indices)
78 glDeleteBuffers(1,&m->vao.indices);
79 if (m->vao.list)
80 glDeleteVertexArrays(1,&m->vao.list);
83 free(m);
86 /* create a mesh for a material */
87 mesh_t *mesh_create_material(material_t *mat)
89 mesh_t *m = mesh_create(GL_TRIANGLES);
90 m->mat = mat;
91 m->t = array_create(ARRAY_TYPE_FLOAT);
92 m->n = array_create(ARRAY_TYPE_FLOAT);
93 return m;
96 /* create a mesh for a colour */
97 mesh_t *mesh_create_colour(colour_t *c)
99 mesh_t *m = mesh_create(GL_TRIANGLES);
100 m->col = malloc(sizeof(colour_t));
101 m->col->r = c->r;
102 m->col->g = c->g;
103 m->col->b = c->b;
104 m->col->a = c->a;
105 m->n = array_create(ARRAY_TYPE_FLOAT);
106 return m;
109 /* duplicate a mesh */
110 mesh_t *mesh_copy(mesh_t *om)
112 mesh_t *m = mesh_create(om->mode);
113 if (om->mat)
114 m->mat = om->mat;
115 m->v = array_copy(om->v);
116 if (om->n)
117 m->n = array_copy(om->n);
118 if (om->t)
119 m->t = array_copy(om->t);
120 m->i = array_copy(om->i);
122 m->option = om->option;
124 return m;
127 /* push a vertex onto a mesh */
128 int mesh_push_point(mesh_t *m, v3_t *v1)
130 int i;
131 for (i=0; i<m->v->length; i+=3) {
132 if (
133 v1->x == AFLOAT(m->v->data,i)
134 && v1->y == AFLOAT(m->v->data,i+1)
135 && v1->z == AFLOAT(m->v->data,i+2)
137 array_push_int(m->i,i/3);
138 return 0;
141 array_push_int(m->i,i/3);
142 array_push_float(m->v,v1->x);
143 array_push_float(m->v,v1->y);
144 array_push_float(m->v,v1->z);
146 return 1;
149 /* push a poly point onto a mesh */
150 int mesh_push_polypoint(mesh_t *m, v3_t *v, v2_t *t)
152 int i;
153 int vi;
154 int ti;
155 for (i=0; (i*3)<m->v->length; i++) {
156 vi = i*3;
157 ti = i*2;
158 if (
159 v->x == AFLOAT(m->v->data,vi)
160 && v->y == AFLOAT(m->v->data,vi+1)
161 && v->z == AFLOAT(m->v->data,vi+2)
162 && t->x == AFLOAT(m->t->data,ti)
163 && t->y == AFLOAT(m->t->data,ti+1)
165 array_push_int(m->i,i);
166 return 0;
169 array_push_int(m->i,i);
170 array_push_v3t(m->v,v);
171 array_push_v2t(m->t,t);
173 return 1;
176 /* push a poly point with normal onto a mesh */
177 int mesh_push_polypoint_n(mesh_t *m, v3_t *v, v3_t *n, v2_t *t)
179 int i;
180 int vi;
181 int ti;
182 for (i=0; (i*3)<m->v->length; i++) {
183 vi = i*3;
184 ti = i*2;
185 if (
186 v->x == AFLOAT(m->v->data,vi)
187 && v->y == AFLOAT(m->v->data,vi+1)
188 && v->z == AFLOAT(m->v->data,vi+2)
189 && n->x == AFLOAT(m->n->data,vi)
190 && n->y == AFLOAT(m->n->data,vi+1)
191 && n->z == AFLOAT(m->n->data,vi+2)
192 && t->x == AFLOAT(m->t->data,ti)
193 && t->y == AFLOAT(m->t->data,ti+1)
195 array_push_int(m->i,i);
196 return 0;
199 array_push_int(m->i,i);
200 array_push_v3t(m->v,v);
201 array_push_v3t(m->n,n);
202 array_push_v2t(m->t,t);
204 return 1;
207 /* push a poly onto a mesh */
208 void mesh_push_poly(mesh_t *m, v3_t *v1, v3_t *v2, v3_t *v3)
210 if (mesh_push_point(m,v1)) {
211 if (m->mat) {
212 array_push_float(m->t,0);
213 array_push_float(m->t,0);
216 if (mesh_push_point(m,v2)) {
217 if (m->mat) {
218 array_push_float(m->t,0);
219 array_push_float(m->t,1);
222 if (mesh_push_point(m,v3)) {
223 if (m->mat) {
224 array_push_float(m->t,1);
225 array_push_float(m->t,1);
230 /* push a quad onto a mesh */
231 void mesh_push_quad(mesh_t *m, v3_t *v1, v3_t *v2, v3_t *v3, v3_t *v4)
233 int i = m->v->length/3;
234 array_push_float(m->v,v1->x);
235 array_push_float(m->v,v1->y);
236 array_push_float(m->v,v1->z);
237 array_push_float(m->v,v2->x);
238 array_push_float(m->v,v2->y);
239 array_push_float(m->v,v2->z);
240 array_push_float(m->v,v3->x);
241 array_push_float(m->v,v3->y);
242 array_push_float(m->v,v3->z);
243 array_push_float(m->v,v4->x);
244 array_push_float(m->v,v4->y);
245 array_push_float(m->v,v4->z);
247 array_push_float(m->t,0);
248 array_push_float(m->t,0);
249 array_push_float(m->t,0);
250 array_push_float(m->t,1);
251 array_push_float(m->t,1);
252 array_push_float(m->t,1);
253 array_push_float(m->t,1);
254 array_push_float(m->t,0);
256 array_push_int(m->i,i);
257 array_push_int(m->i,i+1);
258 array_push_int(m->i,i+3);
259 array_push_int(m->i,i+1);
260 array_push_int(m->i,i+2);
261 array_push_int(m->i,i+3);
264 /* calculate normals for a mesh */
265 void mesh_calc_normals(mesh_t *m)
267 int i;
268 GLuint k[9];
269 v3_t v1;
270 v3_t v2;
271 v3_t v3;
272 v3_t b1;
273 v3_t b2;
274 v3_t normal;
275 int *con = alloca(m->v->length*sizeof(int));
276 memset(con,0,m->v->length*sizeof(int));
278 if (m->n) {
279 m->n->length = 0;
280 }else{
281 m->n = array_create(ARRAY_TYPE_FLOAT);
284 for (i=0; i<m->v->length; i++) {
285 array_push_float(m->n,0);
288 for (i=0; i<m->i->length; i+=3) {
289 k[0] = AUINT(m->i->data,i)*3;
290 k[1] = k[0]+1;
291 k[2] = k[0]+2;
292 k[3] = AUINT(m->i->data,i+1)*3;
293 k[4] = k[3]+1;
294 k[5] = k[3]+2;
295 k[6] = AUINT(m->i->data,i+2)*3;
296 k[7] = k[6]+1;
297 k[8] = k[6]+2;
298 v1.x = AFLOAT(m->v->data,k[0]);
299 v1.y = AFLOAT(m->v->data,k[1]);
300 v1.z = AFLOAT(m->v->data,k[2]);
301 v2.x = AFLOAT(m->v->data,k[3]);
302 v2.y = AFLOAT(m->v->data,k[4]);
303 v2.z = AFLOAT(m->v->data,k[5]);
304 v3.x = AFLOAT(m->v->data,k[6]);
305 v3.y = AFLOAT(m->v->data,k[7]);
306 v3.z = AFLOAT(m->v->data,k[8]);
308 b1.x = v2.x-v1.x;
309 b1.y = v2.y-v1.y;
310 b1.z = v2.z-v1.z;
312 b2.x = v3.x-v1.x;
313 b2.y = v3.y-v1.y;
314 b2.z = v3.z-v1.z;
316 vect_crossproduct(&b1,&b2,&normal);
317 vect_normalise(&normal);
319 con[k[0]] += 1;
320 con[k[1]] += 1;
321 con[k[2]] += 1;
323 AFLOAT(m->n->data,k[0]) += normal.x;
324 AFLOAT(m->n->data,k[1]) += normal.y;
325 AFLOAT(m->n->data,k[2]) += normal.z;
326 AFLOAT(m->n->data,k[3]) += normal.x;
327 AFLOAT(m->n->data,k[4]) += normal.y;
328 AFLOAT(m->n->data,k[5]) += normal.z;
329 AFLOAT(m->n->data,k[6]) += normal.x;
330 AFLOAT(m->n->data,k[7]) += normal.y;
331 AFLOAT(m->n->data,k[8]) += normal.z;
334 for (i=0; i<m->n->length; i+=3) {
335 if (con[i]>1) {
336 AFLOAT(m->n->data,i) /= con[i];
337 AFLOAT(m->n->data,i+1) /= con[i];
338 AFLOAT(m->n->data,i+2) /= con[i];