rev |
line source |
nuclear@4
|
1 /*
|
nuclear@4
|
2 Cubemapper - a program for converting panoramic images into cubemaps
|
nuclear@4
|
3 Copyright (C) 2017 John Tsiombikas <nuclear@member.fsf.org>
|
nuclear@4
|
4
|
nuclear@4
|
5 This program is free software: you can redistribute it and/or modify
|
nuclear@4
|
6 it under the terms of the GNU General Public License as published by
|
nuclear@4
|
7 the Free Software Foundation, either version 3 of the License, or
|
nuclear@4
|
8 (at your option) any later version.
|
nuclear@4
|
9
|
nuclear@4
|
10 This program is distributed in the hope that it will be useful,
|
nuclear@4
|
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
nuclear@4
|
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
nuclear@4
|
13 GNU General Public License for more details.
|
nuclear@4
|
14
|
nuclear@4
|
15 You should have received a copy of the GNU General Public License
|
nuclear@4
|
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
nuclear@4
|
17 */
|
nuclear@0
|
18 #include <stdio.h>
|
nuclear@0
|
19 #include <stdlib.h>
|
nuclear@0
|
20 #include <float.h>
|
nuclear@0
|
21 #include <assert.h>
|
nuclear@0
|
22 #include "opengl.h"
|
nuclear@0
|
23 #include "mesh.h"
|
nuclear@0
|
24 //#include "xform_node.h"
|
nuclear@0
|
25
|
nuclear@0
|
26 #define USE_OLDGL
|
nuclear@0
|
27
|
nuclear@0
|
28 bool Mesh::use_custom_sdr_attr = true;
|
nuclear@0
|
29 int Mesh::global_sdr_loc[NUM_MESH_ATTR] = { 0, 1, 2, 3, 4, 5, 6 };
|
nuclear@0
|
30 /*
|
nuclear@0
|
31 (int)SDR_ATTR_VERTEX,
|
nuclear@0
|
32 (int)SDR_ATTR_NORMAL,
|
nuclear@0
|
33 (int)SDR_ATTR_TANGENT,
|
nuclear@0
|
34 (int)SDR_ATTR_TEXCOORD,
|
nuclear@0
|
35 (int)SDR_ATTR_COLOR,
|
nuclear@0
|
36 -1, -1};
|
nuclear@0
|
37 */
|
nuclear@0
|
38 unsigned int Mesh::intersect_mode = ISECT_DEFAULT;
|
nuclear@0
|
39 float Mesh::vertex_sel_dist = 0.01;
|
nuclear@0
|
40 float Mesh::vis_vecsize = 1.0;
|
nuclear@0
|
41
|
nuclear@0
|
42 Mesh::Mesh()
|
nuclear@0
|
43 {
|
nuclear@0
|
44 clear();
|
nuclear@0
|
45
|
nuclear@0
|
46 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
|
nuclear@0
|
47
|
nuclear@0
|
48 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
49 vattr[i].vbo = buffer_objects[i];
|
nuclear@0
|
50 }
|
nuclear@0
|
51 ibo = buffer_objects[NUM_MESH_ATTR];
|
nuclear@0
|
52 wire_ibo = 0;
|
nuclear@0
|
53 }
|
nuclear@0
|
54
|
nuclear@0
|
55 Mesh::~Mesh()
|
nuclear@0
|
56 {
|
nuclear@0
|
57 glDeleteBuffers(NUM_MESH_ATTR + 1, buffer_objects);
|
nuclear@0
|
58
|
nuclear@0
|
59 if(wire_ibo) {
|
nuclear@0
|
60 glDeleteBuffers(1, &wire_ibo);
|
nuclear@0
|
61 }
|
nuclear@0
|
62 }
|
nuclear@0
|
63
|
nuclear@0
|
64 Mesh::Mesh(const Mesh &rhs)
|
nuclear@0
|
65 {
|
nuclear@0
|
66 clear();
|
nuclear@0
|
67
|
nuclear@0
|
68 glGenBuffers(NUM_MESH_ATTR + 1, buffer_objects);
|
nuclear@0
|
69
|
nuclear@0
|
70 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
71 vattr[i].vbo = buffer_objects[i];
|
nuclear@0
|
72 }
|
nuclear@0
|
73 ibo = buffer_objects[NUM_MESH_ATTR];
|
nuclear@0
|
74 wire_ibo = 0;
|
nuclear@0
|
75
|
nuclear@0
|
76 clone(rhs);
|
nuclear@0
|
77 }
|
nuclear@0
|
78
|
nuclear@0
|
79 Mesh &Mesh::operator =(const Mesh &rhs)
|
nuclear@0
|
80 {
|
nuclear@0
|
81 if(&rhs != this) {
|
nuclear@0
|
82 clone(rhs);
|
nuclear@0
|
83 }
|
nuclear@0
|
84 return *this;
|
nuclear@0
|
85 }
|
nuclear@0
|
86
|
nuclear@0
|
87 bool Mesh::clone(const Mesh &m)
|
nuclear@0
|
88 {
|
nuclear@0
|
89 clear();
|
nuclear@0
|
90
|
nuclear@0
|
91 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
92 if(m.has_attrib(i)) {
|
nuclear@0
|
93 m.get_attrib_data(i); // force validation of the actual data on the source mesh
|
nuclear@0
|
94
|
nuclear@0
|
95 vattr[i].nelem = m.vattr[i].nelem;
|
nuclear@0
|
96 vattr[i].data = m.vattr[i].data; // copy the actual data
|
nuclear@0
|
97 vattr[i].data_valid = true;
|
nuclear@0
|
98 }
|
nuclear@0
|
99 }
|
nuclear@0
|
100
|
nuclear@0
|
101 if(m.is_indexed()) {
|
nuclear@0
|
102 m.get_index_data(); // again, force validation
|
nuclear@0
|
103
|
nuclear@0
|
104 // copy the index data
|
nuclear@0
|
105 idata = m.idata;
|
nuclear@0
|
106 idata_valid = true;
|
nuclear@0
|
107 }
|
nuclear@0
|
108
|
nuclear@0
|
109 name = m.name;
|
nuclear@0
|
110 nverts = m.nverts;
|
nuclear@0
|
111 nfaces = m.nfaces;
|
nuclear@0
|
112
|
nuclear@0
|
113 //bones = m.bones;
|
nuclear@0
|
114
|
nuclear@0
|
115 memcpy(cur_val, m.cur_val, sizeof cur_val);
|
nuclear@0
|
116
|
nuclear@0
|
117 aabb = m.aabb;
|
nuclear@0
|
118 aabb_valid = m.aabb_valid;
|
nuclear@0
|
119 bsph = m.bsph;
|
nuclear@0
|
120 bsph_valid = m.bsph_valid;
|
nuclear@0
|
121
|
nuclear@0
|
122 hitface = m.hitface;
|
nuclear@0
|
123 hitvert = m.hitvert;
|
nuclear@0
|
124
|
nuclear@0
|
125 intersect_mode = m.intersect_mode;
|
nuclear@0
|
126 vertex_sel_dist = m.vertex_sel_dist;
|
nuclear@0
|
127 vis_vecsize = m.vis_vecsize;
|
nuclear@0
|
128
|
nuclear@0
|
129 return true;
|
nuclear@0
|
130 }
|
nuclear@0
|
131
|
nuclear@0
|
132 void Mesh::set_name(const char *name)
|
nuclear@0
|
133 {
|
nuclear@0
|
134 this->name = name;
|
nuclear@0
|
135 }
|
nuclear@0
|
136
|
nuclear@0
|
137 const char *Mesh::get_name() const
|
nuclear@0
|
138 {
|
nuclear@0
|
139 return name.c_str();
|
nuclear@0
|
140 }
|
nuclear@0
|
141
|
nuclear@0
|
142 bool Mesh::has_attrib(int attr) const
|
nuclear@0
|
143 {
|
nuclear@0
|
144 if(attr < 0 || attr >= NUM_MESH_ATTR) {
|
nuclear@0
|
145 return false;
|
nuclear@0
|
146 }
|
nuclear@0
|
147
|
nuclear@0
|
148 // if neither of these is valid, then nobody has set this attribute
|
nuclear@0
|
149 return vattr[attr].vbo_valid || vattr[attr].data_valid;
|
nuclear@0
|
150 }
|
nuclear@0
|
151
|
nuclear@0
|
152 bool Mesh::is_indexed() const
|
nuclear@0
|
153 {
|
nuclear@0
|
154 return ibo_valid || idata_valid;
|
nuclear@0
|
155 }
|
nuclear@0
|
156
|
nuclear@0
|
157 void Mesh::clear()
|
nuclear@0
|
158 {
|
nuclear@0
|
159 //bones.clear();
|
nuclear@0
|
160
|
nuclear@0
|
161 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
162 vattr[i].nelem = 0;
|
nuclear@0
|
163 vattr[i].vbo_valid = false;
|
nuclear@0
|
164 vattr[i].data_valid = false;
|
nuclear@0
|
165 //vattr[i].sdr_loc = -1;
|
nuclear@0
|
166 vattr[i].data.clear();
|
nuclear@0
|
167 }
|
nuclear@0
|
168 ibo_valid = idata_valid = false;
|
nuclear@0
|
169 idata.clear();
|
nuclear@0
|
170
|
nuclear@0
|
171 wire_ibo_valid = false;
|
nuclear@0
|
172
|
nuclear@0
|
173 nverts = nfaces = 0;
|
nuclear@0
|
174
|
nuclear@0
|
175 bsph_valid = false;
|
nuclear@0
|
176 aabb_valid = false;
|
nuclear@0
|
177 }
|
nuclear@0
|
178
|
nuclear@0
|
179 float *Mesh::set_attrib_data(int attrib, int nelem, unsigned int num, const float *data)
|
nuclear@0
|
180 {
|
nuclear@0
|
181 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
|
nuclear@0
|
182 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
|
nuclear@0
|
183 return 0;
|
nuclear@0
|
184 }
|
nuclear@0
|
185
|
nuclear@0
|
186 if(nverts && num != nverts) {
|
nuclear@0
|
187 fprintf(stderr, "%s: attribute count missmatch (%d instead of %d)\n", __FUNCTION__, num, nverts);
|
nuclear@0
|
188 return 0;
|
nuclear@0
|
189 }
|
nuclear@0
|
190 nverts = num;
|
nuclear@0
|
191
|
nuclear@0
|
192 vattr[attrib].data.clear();
|
nuclear@0
|
193 vattr[attrib].nelem = nelem;
|
nuclear@0
|
194 vattr[attrib].data.resize(num * nelem);
|
nuclear@0
|
195
|
nuclear@0
|
196 if(data) {
|
nuclear@0
|
197 memcpy(&vattr[attrib].data[0], data, num * nelem * sizeof *data);
|
nuclear@0
|
198 }
|
nuclear@0
|
199
|
nuclear@0
|
200 vattr[attrib].data_valid = true;
|
nuclear@0
|
201 vattr[attrib].vbo_valid = false;
|
nuclear@0
|
202 return &vattr[attrib].data[0];
|
nuclear@0
|
203 }
|
nuclear@0
|
204
|
nuclear@0
|
205 float *Mesh::get_attrib_data(int attrib)
|
nuclear@0
|
206 {
|
nuclear@0
|
207 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
|
nuclear@0
|
208 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
|
nuclear@0
|
209 return 0;
|
nuclear@0
|
210 }
|
nuclear@0
|
211
|
nuclear@0
|
212 vattr[attrib].vbo_valid = false;
|
nuclear@0
|
213 return (float*)((const Mesh*)this)->get_attrib_data(attrib);
|
nuclear@0
|
214 }
|
nuclear@0
|
215
|
nuclear@0
|
216 const float *Mesh::get_attrib_data(int attrib) const
|
nuclear@0
|
217 {
|
nuclear@0
|
218 if(attrib < 0 || attrib >= NUM_MESH_ATTR) {
|
nuclear@0
|
219 fprintf(stderr, "%s: invalid attrib: %d\n", __FUNCTION__, attrib);
|
nuclear@0
|
220 return 0;
|
nuclear@0
|
221 }
|
nuclear@0
|
222
|
nuclear@0
|
223 if(!vattr[attrib].data_valid) {
|
nuclear@0
|
224 #if GL_ES_VERSION_2_0
|
nuclear@0
|
225 fprintf(stderr, "%s: can't read back attrib data on CrippledGL ES\n", __FUNCTION__);
|
nuclear@0
|
226 return 0;
|
nuclear@0
|
227 #else
|
nuclear@0
|
228 if(!vattr[attrib].vbo_valid) {
|
nuclear@0
|
229 fprintf(stderr, "%s: unavailable attrib: %d\n", __FUNCTION__, attrib);
|
nuclear@0
|
230 return 0;
|
nuclear@0
|
231 }
|
nuclear@0
|
232
|
nuclear@0
|
233 // local data copy is unavailable, grab the data from the vbo
|
nuclear@0
|
234 Mesh *m = (Mesh*)this;
|
nuclear@0
|
235 m->vattr[attrib].data.resize(nverts * vattr[attrib].nelem);
|
nuclear@0
|
236
|
nuclear@0
|
237 glBindBuffer(GL_ARRAY_BUFFER, vattr[attrib].vbo);
|
nuclear@0
|
238 void *data = glMapBuffer(GL_ARRAY_BUFFER, GL_READ_ONLY);
|
nuclear@0
|
239 memcpy(&m->vattr[attrib].data[0], data, nverts * vattr[attrib].nelem * sizeof(float));
|
nuclear@0
|
240 glUnmapBuffer(GL_ARRAY_BUFFER);
|
nuclear@0
|
241
|
nuclear@0
|
242 vattr[attrib].data_valid = true;
|
nuclear@0
|
243 #endif
|
nuclear@0
|
244 }
|
nuclear@0
|
245
|
nuclear@0
|
246 return &vattr[attrib].data[0];
|
nuclear@0
|
247 }
|
nuclear@0
|
248
|
nuclear@0
|
249 void Mesh::set_attrib(int attrib, int idx, const Vec4 &v)
|
nuclear@0
|
250 {
|
nuclear@0
|
251 float *data = get_attrib_data(attrib);
|
nuclear@0
|
252 if(data) {
|
nuclear@0
|
253 data += idx * vattr[attrib].nelem;
|
nuclear@0
|
254 for(int i=0; i<vattr[attrib].nelem; i++) {
|
nuclear@0
|
255 data[i] = v[i];
|
nuclear@0
|
256 }
|
nuclear@0
|
257 }
|
nuclear@0
|
258 }
|
nuclear@0
|
259
|
nuclear@0
|
260 Vec4 Mesh::get_attrib(int attrib, int idx) const
|
nuclear@0
|
261 {
|
nuclear@0
|
262 Vec4 v(0.0, 0.0, 0.0, 1.0);
|
nuclear@0
|
263 const float *data = get_attrib_data(attrib);
|
nuclear@0
|
264 if(data) {
|
nuclear@0
|
265 data += idx * vattr[attrib].nelem;
|
nuclear@0
|
266 for(int i=0; i<vattr[attrib].nelem; i++) {
|
nuclear@0
|
267 v[i] = data[i];
|
nuclear@0
|
268 }
|
nuclear@0
|
269 }
|
nuclear@0
|
270 return v;
|
nuclear@0
|
271 }
|
nuclear@0
|
272
|
nuclear@0
|
273 int Mesh::get_attrib_count(int attrib) const
|
nuclear@0
|
274 {
|
nuclear@0
|
275 return has_attrib(attrib) ? nverts : 0;
|
nuclear@0
|
276 }
|
nuclear@0
|
277
|
nuclear@0
|
278
|
nuclear@0
|
279 unsigned int *Mesh::set_index_data(int num, const unsigned int *indices)
|
nuclear@0
|
280 {
|
nuclear@0
|
281 int nidx = nfaces * 3;
|
nuclear@0
|
282 if(nidx && num != nidx) {
|
nuclear@0
|
283 fprintf(stderr, "%s: index count missmatch (%d instead of %d)\n", __FUNCTION__, num, nidx);
|
nuclear@0
|
284 return 0;
|
nuclear@0
|
285 }
|
nuclear@0
|
286 nfaces = num / 3;
|
nuclear@0
|
287
|
nuclear@0
|
288 idata.clear();
|
nuclear@0
|
289 idata.resize(num);
|
nuclear@0
|
290
|
nuclear@0
|
291 if(indices) {
|
nuclear@0
|
292 memcpy(&idata[0], indices, num * sizeof *indices);
|
nuclear@0
|
293 }
|
nuclear@0
|
294
|
nuclear@0
|
295 idata_valid = true;
|
nuclear@0
|
296 ibo_valid = false;
|
nuclear@0
|
297
|
nuclear@0
|
298 return &idata[0];
|
nuclear@0
|
299 }
|
nuclear@0
|
300
|
nuclear@0
|
301 unsigned int *Mesh::get_index_data()
|
nuclear@0
|
302 {
|
nuclear@0
|
303 ibo_valid = false;
|
nuclear@0
|
304 return (unsigned int*)((const Mesh*)this)->get_index_data();
|
nuclear@0
|
305 }
|
nuclear@0
|
306
|
nuclear@0
|
307 const unsigned int *Mesh::get_index_data() const
|
nuclear@0
|
308 {
|
nuclear@0
|
309 if(!idata_valid) {
|
nuclear@0
|
310 #if GL_ES_VERSION_2_0
|
nuclear@0
|
311 fprintf(stderr, "%s: can't read back index data in CrippledGL ES\n", __FUNCTION__);
|
nuclear@0
|
312 return 0;
|
nuclear@0
|
313 #else
|
nuclear@0
|
314 if(!ibo_valid) {
|
nuclear@0
|
315 fprintf(stderr, "%s: indices unavailable\n", __FUNCTION__);
|
nuclear@0
|
316 return 0;
|
nuclear@0
|
317 }
|
nuclear@0
|
318
|
nuclear@0
|
319 // local data copy is unavailable, gram the data from the ibo
|
nuclear@0
|
320 Mesh *m = (Mesh*)this;
|
nuclear@0
|
321 int nidx = nfaces * 3;
|
nuclear@0
|
322 m->idata.resize(nidx);
|
nuclear@0
|
323
|
nuclear@0
|
324 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
nuclear@0
|
325 void *data = glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_READ_ONLY);
|
nuclear@0
|
326 memcpy(&m->idata[0], data, nidx * sizeof(unsigned int));
|
nuclear@0
|
327 glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER);
|
nuclear@0
|
328
|
nuclear@0
|
329 idata_valid = true;
|
nuclear@0
|
330 #endif
|
nuclear@0
|
331 }
|
nuclear@0
|
332
|
nuclear@0
|
333 return &idata[0];
|
nuclear@0
|
334 }
|
nuclear@0
|
335
|
nuclear@0
|
336 int Mesh::get_index_count() const
|
nuclear@0
|
337 {
|
nuclear@0
|
338 return nfaces * 3;
|
nuclear@0
|
339 }
|
nuclear@0
|
340
|
nuclear@0
|
341 void Mesh::append(const Mesh &mesh)
|
nuclear@0
|
342 {
|
nuclear@0
|
343 unsigned int idxoffs = nverts;
|
nuclear@0
|
344
|
nuclear@0
|
345 if(!nverts) {
|
nuclear@0
|
346 clone(mesh);
|
nuclear@0
|
347 return;
|
nuclear@0
|
348 }
|
nuclear@0
|
349
|
nuclear@0
|
350 nverts += mesh.nverts;
|
nuclear@0
|
351 nfaces += mesh.nfaces;
|
nuclear@0
|
352
|
nuclear@0
|
353 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
354 if(has_attrib(i) && mesh.has_attrib(i)) {
|
nuclear@0
|
355 // force validating the data arrays
|
nuclear@0
|
356 get_attrib_data(i);
|
nuclear@0
|
357 mesh.get_attrib_data(i);
|
nuclear@0
|
358
|
nuclear@0
|
359 // append the mesh data
|
nuclear@0
|
360 vattr[i].data.insert(vattr[i].data.end(), mesh.vattr[i].data.begin(), mesh.vattr[i].data.end());
|
nuclear@0
|
361 }
|
nuclear@0
|
362 }
|
nuclear@0
|
363
|
nuclear@0
|
364 if(ibo_valid || idata_valid) {
|
nuclear@0
|
365 // make index arrays valid
|
nuclear@0
|
366 get_index_data();
|
nuclear@0
|
367 mesh.get_index_data();
|
nuclear@0
|
368
|
nuclear@0
|
369 size_t orig_sz = idata.size();
|
nuclear@0
|
370
|
nuclear@0
|
371 idata.insert(idata.end(), mesh.idata.begin(), mesh.idata.end());
|
nuclear@0
|
372
|
nuclear@0
|
373 // fixup all the new indices
|
nuclear@0
|
374 for(size_t i=orig_sz; i<idata.size(); i++) {
|
nuclear@0
|
375 idata[i] += idxoffs;
|
nuclear@0
|
376 }
|
nuclear@0
|
377 }
|
nuclear@0
|
378
|
nuclear@0
|
379 // fuck everything
|
nuclear@0
|
380 wire_ibo_valid = false;
|
nuclear@0
|
381 aabb_valid = false;
|
nuclear@0
|
382 bsph_valid = false;
|
nuclear@0
|
383 }
|
nuclear@0
|
384
|
nuclear@0
|
385 // assemble a complete vertex by adding all the useful attributes
|
nuclear@0
|
386 void Mesh::vertex(float x, float y, float z)
|
nuclear@0
|
387 {
|
nuclear@0
|
388 cur_val[MESH_ATTR_VERTEX] = Vec4(x, y, z, 1.0f);
|
nuclear@0
|
389 vattr[MESH_ATTR_VERTEX].data_valid = true;
|
nuclear@0
|
390 vattr[MESH_ATTR_VERTEX].nelem = 3;
|
nuclear@0
|
391
|
nuclear@0
|
392 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
393 if(vattr[i].data_valid) {
|
nuclear@0
|
394 for(int j=0; j<vattr[MESH_ATTR_VERTEX].nelem; j++) {
|
nuclear@0
|
395 vattr[i].data.push_back(cur_val[i][j]);
|
nuclear@0
|
396 }
|
nuclear@0
|
397 }
|
nuclear@0
|
398 vattr[i].vbo_valid = false;
|
nuclear@0
|
399 }
|
nuclear@0
|
400
|
nuclear@0
|
401 if(idata_valid) {
|
nuclear@0
|
402 idata.clear();
|
nuclear@0
|
403 }
|
nuclear@0
|
404 ibo_valid = idata_valid = false;
|
nuclear@0
|
405 }
|
nuclear@0
|
406
|
nuclear@0
|
407 void Mesh::normal(float nx, float ny, float nz)
|
nuclear@0
|
408 {
|
nuclear@0
|
409 cur_val[MESH_ATTR_NORMAL] = Vec4(nx, ny, nz, 1.0f);
|
nuclear@0
|
410 vattr[MESH_ATTR_NORMAL].data_valid = true;
|
nuclear@0
|
411 vattr[MESH_ATTR_NORMAL].nelem = 3;
|
nuclear@0
|
412 }
|
nuclear@0
|
413
|
nuclear@0
|
414 void Mesh::tangent(float tx, float ty, float tz)
|
nuclear@0
|
415 {
|
nuclear@0
|
416 cur_val[MESH_ATTR_TANGENT] = Vec4(tx, ty, tz, 1.0f);
|
nuclear@0
|
417 vattr[MESH_ATTR_TANGENT].data_valid = true;
|
nuclear@0
|
418 vattr[MESH_ATTR_TANGENT].nelem = 3;
|
nuclear@0
|
419 }
|
nuclear@0
|
420
|
nuclear@0
|
421 void Mesh::texcoord(float u, float v, float w)
|
nuclear@0
|
422 {
|
nuclear@0
|
423 cur_val[MESH_ATTR_TEXCOORD] = Vec4(u, v, w, 1.0f);
|
nuclear@0
|
424 vattr[MESH_ATTR_TEXCOORD].data_valid = true;
|
nuclear@0
|
425 vattr[MESH_ATTR_TEXCOORD].nelem = 3;
|
nuclear@0
|
426 }
|
nuclear@0
|
427
|
nuclear@0
|
428 void Mesh::boneweights(float w1, float w2, float w3, float w4)
|
nuclear@0
|
429 {
|
nuclear@0
|
430 cur_val[MESH_ATTR_BONEWEIGHTS] = Vec4(w1, w2, w3, w4);
|
nuclear@0
|
431 vattr[MESH_ATTR_BONEWEIGHTS].data_valid = true;
|
nuclear@0
|
432 vattr[MESH_ATTR_BONEWEIGHTS].nelem = 4;
|
nuclear@0
|
433 }
|
nuclear@0
|
434
|
nuclear@0
|
435 void Mesh::boneidx(int idx1, int idx2, int idx3, int idx4)
|
nuclear@0
|
436 {
|
nuclear@0
|
437 cur_val[MESH_ATTR_BONEIDX] = Vec4(idx1, idx2, idx3, idx4);
|
nuclear@0
|
438 vattr[MESH_ATTR_BONEIDX].data_valid = true;
|
nuclear@0
|
439 vattr[MESH_ATTR_BONEIDX].nelem = 4;
|
nuclear@0
|
440 }
|
nuclear@0
|
441
|
nuclear@0
|
442 int Mesh::get_poly_count() const
|
nuclear@0
|
443 {
|
nuclear@0
|
444 if(nfaces) {
|
nuclear@0
|
445 return nfaces;
|
nuclear@0
|
446 }
|
nuclear@0
|
447 if(nverts) {
|
nuclear@0
|
448 return nverts / 3;
|
nuclear@0
|
449 }
|
nuclear@0
|
450 return 0;
|
nuclear@0
|
451 }
|
nuclear@0
|
452
|
nuclear@0
|
453 /// static function
|
nuclear@0
|
454 void Mesh::set_attrib_location(int attr, int loc)
|
nuclear@0
|
455 {
|
nuclear@0
|
456 if(attr < 0 || attr >= NUM_MESH_ATTR) {
|
nuclear@0
|
457 return;
|
nuclear@0
|
458 }
|
nuclear@0
|
459 Mesh::global_sdr_loc[attr] = loc;
|
nuclear@0
|
460 }
|
nuclear@0
|
461
|
nuclear@0
|
462 /// static function
|
nuclear@0
|
463 int Mesh::get_attrib_location(int attr)
|
nuclear@0
|
464 {
|
nuclear@0
|
465 if(attr < 0 || attr >= NUM_MESH_ATTR) {
|
nuclear@0
|
466 return -1;
|
nuclear@0
|
467 }
|
nuclear@0
|
468 return Mesh::global_sdr_loc[attr];
|
nuclear@0
|
469 }
|
nuclear@0
|
470
|
nuclear@0
|
471 /// static function
|
nuclear@0
|
472 void Mesh::clear_attrib_locations()
|
nuclear@0
|
473 {
|
nuclear@0
|
474 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
475 Mesh::global_sdr_loc[i] = -1;
|
nuclear@0
|
476 }
|
nuclear@0
|
477 }
|
nuclear@0
|
478
|
nuclear@0
|
479 /// static function
|
nuclear@0
|
480 void Mesh::set_vis_vecsize(float sz)
|
nuclear@0
|
481 {
|
nuclear@0
|
482 Mesh::vis_vecsize = sz;
|
nuclear@0
|
483 }
|
nuclear@0
|
484
|
nuclear@0
|
485 float Mesh::get_vis_vecsize()
|
nuclear@0
|
486 {
|
nuclear@0
|
487 return Mesh::vis_vecsize;
|
nuclear@0
|
488 }
|
nuclear@0
|
489
|
nuclear@0
|
490 void Mesh::apply_xform(const Mat4 &xform)
|
nuclear@0
|
491 {
|
nuclear@0
|
492 Mat4 dir_xform = xform.upper3x3();
|
nuclear@0
|
493 apply_xform(xform, dir_xform);
|
nuclear@0
|
494 }
|
nuclear@0
|
495
|
nuclear@0
|
496 void Mesh::apply_xform(const Mat4 &xform, const Mat4 &dir_xform)
|
nuclear@0
|
497 {
|
nuclear@0
|
498 for(unsigned int i=0; i<nverts; i++) {
|
nuclear@0
|
499 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
|
nuclear@0
|
500 set_attrib(MESH_ATTR_VERTEX, i, xform * v);
|
nuclear@0
|
501
|
nuclear@0
|
502 if(has_attrib(MESH_ATTR_NORMAL)) {
|
nuclear@0
|
503 Vec3 n = get_attrib(MESH_ATTR_NORMAL, i).xyz();
|
nuclear@0
|
504 set_attrib(MESH_ATTR_NORMAL, i, Vec4(dir_xform * n));
|
nuclear@0
|
505 }
|
nuclear@0
|
506 if(has_attrib(MESH_ATTR_TANGENT)) {
|
nuclear@0
|
507 Vec3 t = get_attrib(MESH_ATTR_TANGENT, i).xyz();
|
nuclear@0
|
508 set_attrib(MESH_ATTR_TANGENT, i, Vec4(dir_xform * t));
|
nuclear@0
|
509 }
|
nuclear@0
|
510 }
|
nuclear@0
|
511 }
|
nuclear@0
|
512
|
nuclear@0
|
513 void Mesh::flip()
|
nuclear@0
|
514 {
|
nuclear@0
|
515 flip_faces();
|
nuclear@0
|
516 flip_normals();
|
nuclear@0
|
517 }
|
nuclear@0
|
518
|
nuclear@0
|
519 void Mesh::flip_faces()
|
nuclear@0
|
520 {
|
nuclear@0
|
521 if(is_indexed()) {
|
nuclear@0
|
522 unsigned int *indices = get_index_data();
|
nuclear@0
|
523 if(!indices) return;
|
nuclear@0
|
524
|
nuclear@0
|
525 int idxnum = get_index_count();
|
nuclear@0
|
526 for(int i=0; i<idxnum; i+=3) {
|
nuclear@0
|
527 unsigned int tmp = indices[i + 2];
|
nuclear@0
|
528 indices[i + 2] = indices[i + 1];
|
nuclear@0
|
529 indices[i + 1] = tmp;
|
nuclear@0
|
530 }
|
nuclear@0
|
531
|
nuclear@0
|
532 } else {
|
nuclear@0
|
533 Vec3 *verts = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
|
nuclear@0
|
534 if(!verts) return;
|
nuclear@0
|
535
|
nuclear@0
|
536 int vnum = get_attrib_count(MESH_ATTR_VERTEX);
|
nuclear@0
|
537 for(int i=0; i<vnum; i+=3) {
|
nuclear@0
|
538 Vec3 tmp = verts[i + 2];
|
nuclear@0
|
539 verts[i + 2] = verts[i + 1];
|
nuclear@0
|
540 verts[i + 1] = tmp;
|
nuclear@0
|
541 }
|
nuclear@0
|
542 }
|
nuclear@0
|
543 }
|
nuclear@0
|
544
|
nuclear@0
|
545 void Mesh::flip_normals()
|
nuclear@0
|
546 {
|
nuclear@0
|
547 Vec3 *normals = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
|
nuclear@0
|
548 if(!normals) return;
|
nuclear@0
|
549
|
nuclear@0
|
550 int num = get_attrib_count(MESH_ATTR_NORMAL);
|
nuclear@0
|
551 for(int i=0; i<num; i++) {
|
nuclear@0
|
552 normals[i] = -normals[i];
|
nuclear@0
|
553 }
|
nuclear@0
|
554 }
|
nuclear@0
|
555
|
nuclear@0
|
556 /*
|
nuclear@0
|
557 int Mesh::add_bone(XFormNode *bone)
|
nuclear@0
|
558 {
|
nuclear@0
|
559 int idx = bones.size();
|
nuclear@0
|
560 bones.push_back(bone);
|
nuclear@0
|
561 return idx;
|
nuclear@0
|
562 }
|
nuclear@0
|
563
|
nuclear@0
|
564 const XFormNode *Mesh::get_bone(int idx) const
|
nuclear@0
|
565 {
|
nuclear@0
|
566 if(idx < 0 || idx >= (int)bones.size()) {
|
nuclear@0
|
567 return 0;
|
nuclear@0
|
568 }
|
nuclear@0
|
569 return bones[idx];
|
nuclear@0
|
570 }
|
nuclear@0
|
571
|
nuclear@0
|
572 int Mesh::get_bones_count() const
|
nuclear@0
|
573 {
|
nuclear@0
|
574 return (int)bones.size();
|
nuclear@0
|
575 }
|
nuclear@0
|
576 */
|
nuclear@0
|
577
|
nuclear@0
|
578 bool Mesh::pre_draw() const
|
nuclear@0
|
579 {
|
nuclear@0
|
580 cur_sdr = 0;
|
nuclear@0
|
581 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
|
nuclear@0
|
582
|
nuclear@0
|
583 ((Mesh*)this)->update_buffers();
|
nuclear@0
|
584
|
nuclear@0
|
585 if(!vattr[MESH_ATTR_VERTEX].vbo_valid) {
|
nuclear@0
|
586 fprintf(stderr, "%s: invalid vertex buffer\n", __FUNCTION__);
|
nuclear@0
|
587 return false;
|
nuclear@0
|
588 }
|
nuclear@0
|
589
|
nuclear@0
|
590 if(cur_sdr && use_custom_sdr_attr) {
|
nuclear@0
|
591 // rendering with shaders
|
nuclear@0
|
592 if(global_sdr_loc[MESH_ATTR_VERTEX] == -1) {
|
nuclear@0
|
593 fprintf(stderr, "%s: shader attribute location for vertices unset\n", __FUNCTION__);
|
nuclear@0
|
594 return false;
|
nuclear@0
|
595 }
|
nuclear@0
|
596
|
nuclear@0
|
597 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
598 int loc = global_sdr_loc[i];
|
nuclear@0
|
599 if(loc >= 0 && vattr[i].vbo_valid) {
|
nuclear@0
|
600 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
|
nuclear@0
|
601 glVertexAttribPointer(loc, vattr[i].nelem, GL_FLOAT, GL_FALSE, 0, 0);
|
nuclear@0
|
602 glEnableVertexAttribArray(loc);
|
nuclear@0
|
603 }
|
nuclear@0
|
604 }
|
nuclear@0
|
605 } else {
|
nuclear@0
|
606 #ifndef GL_ES_VERSION_2_0
|
nuclear@0
|
607 // rendering with fixed-function (not available in GLES2)
|
nuclear@0
|
608 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_VERTEX].vbo);
|
nuclear@0
|
609 glVertexPointer(vattr[MESH_ATTR_VERTEX].nelem, GL_FLOAT, 0, 0);
|
nuclear@0
|
610 glEnableClientState(GL_VERTEX_ARRAY);
|
nuclear@0
|
611
|
nuclear@0
|
612 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
|
nuclear@0
|
613 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_NORMAL].vbo);
|
nuclear@0
|
614 glNormalPointer(GL_FLOAT, 0, 0);
|
nuclear@0
|
615 glEnableClientState(GL_NORMAL_ARRAY);
|
nuclear@0
|
616 }
|
nuclear@0
|
617 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
|
nuclear@0
|
618 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_TEXCOORD].vbo);
|
nuclear@0
|
619 glTexCoordPointer(vattr[MESH_ATTR_TEXCOORD].nelem, GL_FLOAT, 0, 0);
|
nuclear@0
|
620 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
nuclear@0
|
621 }
|
nuclear@0
|
622 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
|
nuclear@0
|
623 glBindBuffer(GL_ARRAY_BUFFER, vattr[MESH_ATTR_COLOR].vbo);
|
nuclear@0
|
624 glColorPointer(vattr[MESH_ATTR_COLOR].nelem, GL_FLOAT, 0, 0);
|
nuclear@0
|
625 glEnableClientState(GL_COLOR_ARRAY);
|
nuclear@0
|
626 }
|
nuclear@0
|
627 #endif
|
nuclear@0
|
628 }
|
nuclear@0
|
629 glBindBuffer(GL_ARRAY_BUFFER, 0);
|
nuclear@0
|
630
|
nuclear@0
|
631 return true;
|
nuclear@0
|
632 }
|
nuclear@0
|
633
|
nuclear@0
|
634 void Mesh::draw() const
|
nuclear@0
|
635 {
|
nuclear@0
|
636 if(!pre_draw()) return;
|
nuclear@0
|
637
|
nuclear@0
|
638 if(ibo_valid) {
|
nuclear@0
|
639 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
nuclear@0
|
640 glDrawElements(GL_TRIANGLES, nfaces * 3, GL_UNSIGNED_INT, 0);
|
nuclear@0
|
641 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
nuclear@0
|
642 } else {
|
nuclear@0
|
643 glDrawArrays(GL_TRIANGLES, 0, nverts);
|
nuclear@0
|
644 }
|
nuclear@0
|
645
|
nuclear@0
|
646 post_draw();
|
nuclear@0
|
647 }
|
nuclear@0
|
648
|
nuclear@0
|
649 void Mesh::post_draw() const
|
nuclear@0
|
650 {
|
nuclear@0
|
651 if(cur_sdr && use_custom_sdr_attr) {
|
nuclear@0
|
652 // rendered with shaders
|
nuclear@0
|
653 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
654 int loc = global_sdr_loc[i];
|
nuclear@0
|
655 if(loc >= 0 && vattr[i].vbo_valid) {
|
nuclear@0
|
656 glDisableVertexAttribArray(loc);
|
nuclear@0
|
657 }
|
nuclear@0
|
658 }
|
nuclear@0
|
659 } else {
|
nuclear@0
|
660 #ifndef GL_ES_VERSION_2_0
|
nuclear@0
|
661 // rendered with fixed-function
|
nuclear@0
|
662 glDisableClientState(GL_VERTEX_ARRAY);
|
nuclear@0
|
663 if(vattr[MESH_ATTR_NORMAL].vbo_valid) {
|
nuclear@0
|
664 glDisableClientState(GL_NORMAL_ARRAY);
|
nuclear@0
|
665 }
|
nuclear@0
|
666 if(vattr[MESH_ATTR_TEXCOORD].vbo_valid) {
|
nuclear@0
|
667 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
nuclear@0
|
668 }
|
nuclear@0
|
669 if(vattr[MESH_ATTR_COLOR].vbo_valid) {
|
nuclear@0
|
670 glDisableClientState(GL_COLOR_ARRAY);
|
nuclear@0
|
671 }
|
nuclear@0
|
672 #endif
|
nuclear@0
|
673 }
|
nuclear@0
|
674 }
|
nuclear@0
|
675
|
nuclear@0
|
676 void Mesh::draw_wire() const
|
nuclear@0
|
677 {
|
nuclear@0
|
678 if(!pre_draw()) return;
|
nuclear@0
|
679
|
nuclear@0
|
680 ((Mesh*)this)->update_wire_ibo();
|
nuclear@0
|
681
|
nuclear@0
|
682 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
|
nuclear@0
|
683 glDrawElements(GL_LINES, nfaces * 6, GL_UNSIGNED_INT, 0);
|
nuclear@0
|
684 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
nuclear@0
|
685
|
nuclear@0
|
686 post_draw();
|
nuclear@0
|
687 }
|
nuclear@0
|
688
|
nuclear@0
|
689 void Mesh::draw_vertices() const
|
nuclear@0
|
690 {
|
nuclear@0
|
691 if(!pre_draw()) return;
|
nuclear@0
|
692
|
nuclear@0
|
693 glDrawArrays(GL_POINTS, 0, nverts);
|
nuclear@0
|
694
|
nuclear@0
|
695 post_draw();
|
nuclear@0
|
696 }
|
nuclear@0
|
697
|
nuclear@0
|
698 void Mesh::draw_normals() const
|
nuclear@0
|
699 {
|
nuclear@0
|
700 #ifdef USE_OLDGL
|
nuclear@0
|
701 int cur_sdr = 0;
|
nuclear@0
|
702 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
|
nuclear@0
|
703
|
nuclear@0
|
704 Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
|
nuclear@0
|
705 Vec3 *norm = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
|
nuclear@0
|
706 if(!varr || !norm) {
|
nuclear@0
|
707 return;
|
nuclear@0
|
708 }
|
nuclear@0
|
709
|
nuclear@0
|
710 glBegin(GL_LINES);
|
nuclear@0
|
711 if(cur_sdr && use_custom_sdr_attr) {
|
nuclear@0
|
712 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
|
nuclear@0
|
713 if(vert_loc < 0) {
|
nuclear@0
|
714 glEnd();
|
nuclear@0
|
715 return;
|
nuclear@0
|
716 }
|
nuclear@0
|
717
|
nuclear@0
|
718 for(size_t i=0; i<nverts; i++) {
|
nuclear@0
|
719 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
|
nuclear@0
|
720 Vec3 end = varr[i] + norm[i] * vis_vecsize;
|
nuclear@0
|
721 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
|
nuclear@0
|
722 }
|
nuclear@0
|
723 } else {
|
nuclear@0
|
724 for(size_t i=0; i<nverts; i++) {
|
nuclear@0
|
725 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
|
nuclear@0
|
726 Vec3 end = varr[i] + norm[i] * vis_vecsize;
|
nuclear@0
|
727 glVertex3f(end.x, end.y, end.z);
|
nuclear@0
|
728 }
|
nuclear@0
|
729 }
|
nuclear@0
|
730 glEnd();
|
nuclear@0
|
731 #endif // USE_OLDGL
|
nuclear@0
|
732 }
|
nuclear@0
|
733
|
nuclear@0
|
734 void Mesh::draw_tangents() const
|
nuclear@0
|
735 {
|
nuclear@0
|
736 #ifdef USE_OLDGL
|
nuclear@0
|
737 int cur_sdr = 0;
|
nuclear@0
|
738 glGetIntegerv(GL_CURRENT_PROGRAM, &cur_sdr);
|
nuclear@0
|
739
|
nuclear@0
|
740 Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
|
nuclear@0
|
741 Vec3 *tang = (Vec3*)get_attrib_data(MESH_ATTR_TANGENT);
|
nuclear@0
|
742 if(!varr || !tang) {
|
nuclear@0
|
743 return;
|
nuclear@0
|
744 }
|
nuclear@0
|
745
|
nuclear@0
|
746 glBegin(GL_LINES);
|
nuclear@0
|
747 if(cur_sdr && use_custom_sdr_attr) {
|
nuclear@0
|
748 int vert_loc = global_sdr_loc[MESH_ATTR_VERTEX];
|
nuclear@0
|
749 if(vert_loc < 0) {
|
nuclear@0
|
750 glEnd();
|
nuclear@0
|
751 return;
|
nuclear@0
|
752 }
|
nuclear@0
|
753
|
nuclear@0
|
754 for(size_t i=0; i<nverts; i++) {
|
nuclear@0
|
755 glVertexAttrib3f(vert_loc, varr[i].x, varr[i].y, varr[i].z);
|
nuclear@0
|
756 Vec3 end = varr[i] + tang[i] * vis_vecsize;
|
nuclear@0
|
757 glVertexAttrib3f(vert_loc, end.x, end.y, end.z);
|
nuclear@0
|
758 }
|
nuclear@0
|
759 } else {
|
nuclear@0
|
760 for(size_t i=0; i<nverts; i++) {
|
nuclear@0
|
761 glVertex3f(varr[i].x, varr[i].y, varr[i].z);
|
nuclear@0
|
762 Vec3 end = varr[i] + tang[i] * vis_vecsize;
|
nuclear@0
|
763 glVertex3f(end.x, end.y, end.z);
|
nuclear@0
|
764 }
|
nuclear@0
|
765 }
|
nuclear@0
|
766 glEnd();
|
nuclear@0
|
767 #endif // USE_OLDGL
|
nuclear@0
|
768 }
|
nuclear@0
|
769
|
nuclear@0
|
770 void Mesh::get_aabbox(Vec3 *vmin, Vec3 *vmax) const
|
nuclear@0
|
771 {
|
nuclear@0
|
772 if(!aabb_valid) {
|
nuclear@0
|
773 ((Mesh*)this)->calc_aabb();
|
nuclear@0
|
774 }
|
nuclear@0
|
775 *vmin = aabb.min;
|
nuclear@0
|
776 *vmax = aabb.max;
|
nuclear@0
|
777 }
|
nuclear@0
|
778
|
nuclear@0
|
779 const AABox &Mesh::get_aabbox() const
|
nuclear@0
|
780 {
|
nuclear@0
|
781 if(!aabb_valid) {
|
nuclear@0
|
782 ((Mesh*)this)->calc_aabb();
|
nuclear@0
|
783 }
|
nuclear@0
|
784 return aabb;
|
nuclear@0
|
785 }
|
nuclear@0
|
786
|
nuclear@0
|
787 float Mesh::get_bsphere(Vec3 *center, float *rad) const
|
nuclear@0
|
788 {
|
nuclear@0
|
789 if(!bsph_valid) {
|
nuclear@0
|
790 ((Mesh*)this)->calc_bsph();
|
nuclear@0
|
791 }
|
nuclear@0
|
792 *center = bsph.center;
|
nuclear@0
|
793 *rad = bsph.radius;
|
nuclear@0
|
794 return bsph.radius;
|
nuclear@0
|
795 }
|
nuclear@0
|
796
|
nuclear@0
|
797 const Sphere &Mesh::get_bsphere() const
|
nuclear@0
|
798 {
|
nuclear@0
|
799 if(!bsph_valid) {
|
nuclear@0
|
800 ((Mesh*)this)->calc_bsph();
|
nuclear@0
|
801 }
|
nuclear@0
|
802 return bsph;
|
nuclear@0
|
803 }
|
nuclear@0
|
804
|
nuclear@0
|
805 /// static function
|
nuclear@0
|
806 void Mesh::set_intersect_mode(unsigned int mode)
|
nuclear@0
|
807 {
|
nuclear@0
|
808 Mesh::intersect_mode = mode;
|
nuclear@0
|
809 }
|
nuclear@0
|
810
|
nuclear@0
|
811 /// static function
|
nuclear@0
|
812 unsigned int Mesh::get_intersect_mode()
|
nuclear@0
|
813 {
|
nuclear@0
|
814 return Mesh::intersect_mode;
|
nuclear@0
|
815 }
|
nuclear@0
|
816
|
nuclear@0
|
817 /// static function
|
nuclear@0
|
818 void Mesh::set_vertex_select_distance(float dist)
|
nuclear@0
|
819 {
|
nuclear@0
|
820 Mesh::vertex_sel_dist = dist;
|
nuclear@0
|
821 }
|
nuclear@0
|
822
|
nuclear@0
|
823 /// static function
|
nuclear@0
|
824 float Mesh::get_vertex_select_distance()
|
nuclear@0
|
825 {
|
nuclear@0
|
826 return Mesh::vertex_sel_dist;
|
nuclear@0
|
827 }
|
nuclear@0
|
828
|
nuclear@0
|
829 bool Mesh::intersect(const Ray &ray, HitPoint *hit) const
|
nuclear@0
|
830 {
|
nuclear@0
|
831 assert((Mesh::intersect_mode & (ISECT_VERTICES | ISECT_FACE)) != (ISECT_VERTICES | ISECT_FACE));
|
nuclear@0
|
832
|
nuclear@0
|
833 const Vec3 *varr = (Vec3*)get_attrib_data(MESH_ATTR_VERTEX);
|
nuclear@0
|
834 const Vec3 *narr = (Vec3*)get_attrib_data(MESH_ATTR_NORMAL);
|
nuclear@0
|
835 if(!varr) {
|
nuclear@0
|
836 return false;
|
nuclear@0
|
837 }
|
nuclear@0
|
838 const unsigned int *idxarr = get_index_data();
|
nuclear@0
|
839
|
nuclear@0
|
840 // first test with the bounding box
|
nuclear@0
|
841 AABox box;
|
nuclear@0
|
842 get_aabbox(&box.min, &box.max);
|
nuclear@0
|
843 if(!box.intersect(ray)) {
|
nuclear@0
|
844 return false;
|
nuclear@0
|
845 }
|
nuclear@0
|
846
|
nuclear@0
|
847 HitPoint nearest_hit;
|
nuclear@0
|
848 nearest_hit.dist = FLT_MAX;
|
nuclear@0
|
849 nearest_hit.obj = 0;
|
nuclear@0
|
850
|
nuclear@0
|
851 if(Mesh::intersect_mode & ISECT_VERTICES) {
|
nuclear@0
|
852 // we asked for "intersections" with the vertices of the mesh
|
nuclear@0
|
853 long nearest_vidx = -1;
|
nuclear@0
|
854 float thres_sq = Mesh::vertex_sel_dist * Mesh::vertex_sel_dist;
|
nuclear@0
|
855
|
nuclear@0
|
856 for(unsigned int i=0; i<nverts; i++) {
|
nuclear@0
|
857
|
nuclear@0
|
858 if((Mesh::intersect_mode & ISECT_FRONT) && dot(narr[i], ray.dir) > 0) {
|
nuclear@0
|
859 continue;
|
nuclear@0
|
860 }
|
nuclear@0
|
861
|
nuclear@0
|
862 // project the vertex onto the ray line
|
nuclear@0
|
863 float t = dot(varr[i] - ray.origin, ray.dir);
|
nuclear@0
|
864 Vec3 vproj = ray.origin + ray.dir * t;
|
nuclear@0
|
865
|
nuclear@0
|
866 float dist_sq = length_sq(vproj - varr[i]);
|
nuclear@0
|
867 if(dist_sq < thres_sq) {
|
nuclear@0
|
868 if(!hit) {
|
nuclear@0
|
869 return true;
|
nuclear@0
|
870 }
|
nuclear@0
|
871 if(t < nearest_hit.dist) {
|
nuclear@0
|
872 nearest_hit.dist = t;
|
nuclear@0
|
873 nearest_vidx = i;
|
nuclear@0
|
874 }
|
nuclear@0
|
875 }
|
nuclear@0
|
876 }
|
nuclear@0
|
877
|
nuclear@0
|
878 if(nearest_vidx != -1) {
|
nuclear@0
|
879 hitvert = varr[nearest_vidx];
|
nuclear@0
|
880 nearest_hit.obj = &hitvert;
|
nuclear@0
|
881 }
|
nuclear@0
|
882
|
nuclear@0
|
883 } else {
|
nuclear@0
|
884 // regular intersection test with polygons
|
nuclear@0
|
885
|
nuclear@0
|
886 for(unsigned int i=0; i<nfaces; i++) {
|
nuclear@0
|
887 Triangle face(i, varr, idxarr);
|
nuclear@0
|
888
|
nuclear@0
|
889 // ignore back-facing polygons if the mode flags include ISECT_FRONT
|
nuclear@0
|
890 if((Mesh::intersect_mode & ISECT_FRONT) && dot(face.get_normal(), ray.dir) > 0) {
|
nuclear@0
|
891 continue;
|
nuclear@0
|
892 }
|
nuclear@0
|
893
|
nuclear@0
|
894 HitPoint fhit;
|
nuclear@0
|
895 if(face.intersect(ray, hit ? &fhit : 0)) {
|
nuclear@0
|
896 if(!hit) {
|
nuclear@0
|
897 return true;
|
nuclear@0
|
898 }
|
nuclear@0
|
899 if(fhit.dist < nearest_hit.dist) {
|
nuclear@0
|
900 nearest_hit = fhit;
|
nuclear@0
|
901 hitface = face;
|
nuclear@0
|
902 }
|
nuclear@0
|
903 }
|
nuclear@0
|
904 }
|
nuclear@0
|
905 }
|
nuclear@0
|
906
|
nuclear@0
|
907 if(nearest_hit.obj) {
|
nuclear@0
|
908 if(hit) {
|
nuclear@0
|
909 *hit = nearest_hit;
|
nuclear@0
|
910
|
nuclear@0
|
911 // if we are interested in the mesh and not the faces set obj to this
|
nuclear@0
|
912 if(Mesh::intersect_mode & ISECT_FACE) {
|
nuclear@0
|
913 hit->obj = &hitface;
|
nuclear@0
|
914 } else if(Mesh::intersect_mode & ISECT_VERTICES) {
|
nuclear@0
|
915 hit->obj = &hitvert;
|
nuclear@0
|
916 } else {
|
nuclear@0
|
917 hit->obj = this;
|
nuclear@0
|
918 }
|
nuclear@0
|
919 }
|
nuclear@0
|
920 return true;
|
nuclear@0
|
921 }
|
nuclear@0
|
922 return false;
|
nuclear@0
|
923 }
|
nuclear@0
|
924
|
nuclear@0
|
925
|
nuclear@0
|
926 // texture coordinate manipulation
|
nuclear@0
|
927 void Mesh::texcoord_apply_xform(const Mat4 &xform)
|
nuclear@0
|
928 {
|
nuclear@0
|
929 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
|
nuclear@0
|
930 return;
|
nuclear@0
|
931 }
|
nuclear@0
|
932
|
nuclear@0
|
933 for(unsigned int i=0; i<nverts; i++) {
|
nuclear@0
|
934 Vec4 tc = get_attrib(MESH_ATTR_TEXCOORD, i);
|
nuclear@0
|
935 set_attrib(MESH_ATTR_TEXCOORD, i, xform * tc);
|
nuclear@0
|
936 }
|
nuclear@0
|
937 }
|
nuclear@0
|
938
|
nuclear@0
|
939 void Mesh::texcoord_gen_plane(const Vec3 &norm, const Vec3 &tang)
|
nuclear@0
|
940 {
|
nuclear@0
|
941 if(!nverts) return;
|
nuclear@0
|
942
|
nuclear@0
|
943 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
|
nuclear@0
|
944 // allocate texture coordinate attribute array
|
nuclear@0
|
945 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
|
nuclear@0
|
946 }
|
nuclear@0
|
947
|
nuclear@0
|
948 Vec3 n = normalize(norm);
|
nuclear@0
|
949 Vec3 b = normalize(cross(n, tang));
|
nuclear@0
|
950 Vec3 t = cross(b, n);
|
nuclear@0
|
951
|
nuclear@0
|
952 for(unsigned int i=0; i<nverts; i++) {
|
nuclear@0
|
953 Vec3 pos = get_attrib(MESH_ATTR_VERTEX, i).xyz();
|
nuclear@0
|
954
|
nuclear@0
|
955 // distance along the tangent direction
|
nuclear@0
|
956 float u = dot(pos, t);
|
nuclear@0
|
957 // distance along the bitangent direction
|
nuclear@0
|
958 float v = dot(pos, b);
|
nuclear@0
|
959
|
nuclear@0
|
960 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
|
nuclear@0
|
961 }
|
nuclear@0
|
962 }
|
nuclear@0
|
963
|
nuclear@0
|
964 void Mesh::texcoord_gen_box()
|
nuclear@0
|
965 {
|
nuclear@0
|
966 if(!nverts || !has_attrib(MESH_ATTR_NORMAL)) return;
|
nuclear@0
|
967
|
nuclear@0
|
968 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
|
nuclear@0
|
969 // allocate texture coordinate attribute array
|
nuclear@0
|
970 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
|
nuclear@0
|
971 }
|
nuclear@0
|
972
|
nuclear@0
|
973 for(unsigned int i=0; i<nverts; i++) {
|
nuclear@0
|
974 Vec3 pos = Vec3(get_attrib(MESH_ATTR_VERTEX, i)) * 0.5 + Vec3(0.5, 0.5, 0.5);
|
nuclear@0
|
975 Vec3 norm = get_attrib(MESH_ATTR_NORMAL, i).xyz();
|
nuclear@0
|
976
|
nuclear@0
|
977 float abs_nx = fabs(norm.x);
|
nuclear@0
|
978 float abs_ny = fabs(norm.y);
|
nuclear@0
|
979 float abs_nz = fabs(norm.z);
|
nuclear@0
|
980 int dom = abs_nx > abs_ny && abs_nx > abs_nz ? 0 : (abs_ny > abs_nz ? 1 : 2);
|
nuclear@0
|
981
|
nuclear@0
|
982 float uv[2], *uvptr = uv;
|
nuclear@0
|
983 for(int j=0; j<3; j++) {
|
nuclear@0
|
984 if(j == dom) continue; // skip dominant axis
|
nuclear@0
|
985
|
nuclear@0
|
986 *uvptr++ = pos[j];
|
nuclear@0
|
987 }
|
nuclear@0
|
988 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(uv[0], uv[1], 0, 1));
|
nuclear@0
|
989 }
|
nuclear@0
|
990 }
|
nuclear@0
|
991
|
nuclear@0
|
992 void Mesh::texcoord_gen_cylinder()
|
nuclear@0
|
993 {
|
nuclear@0
|
994 if(!nverts) return;
|
nuclear@0
|
995
|
nuclear@0
|
996 if(!has_attrib(MESH_ATTR_TEXCOORD)) {
|
nuclear@0
|
997 // allocate texture coordinate attribute array
|
nuclear@0
|
998 set_attrib_data(MESH_ATTR_TEXCOORD, 2, nverts);
|
nuclear@0
|
999 }
|
nuclear@0
|
1000
|
nuclear@0
|
1001 for(unsigned int i=0; i<nverts; i++) {
|
nuclear@0
|
1002 Vec3 pos = get_attrib(MESH_ATTR_VERTEX, i).xyz();
|
nuclear@0
|
1003
|
nuclear@0
|
1004 float rho = sqrt(pos.x * pos.x + pos.z * pos.z);
|
nuclear@0
|
1005 float theta = rho == 0.0 ? 0.0 : atan2(pos.z / rho, pos.x / rho);
|
nuclear@0
|
1006
|
nuclear@0
|
1007 float u = theta / (2.0 * M_PI) + 0.5;
|
nuclear@0
|
1008 float v = pos.y;
|
nuclear@0
|
1009
|
nuclear@0
|
1010 set_attrib(MESH_ATTR_TEXCOORD, i, Vec4(u, v, 0, 1));
|
nuclear@0
|
1011 }
|
nuclear@0
|
1012 }
|
nuclear@0
|
1013
|
nuclear@0
|
1014
|
nuclear@0
|
1015 bool Mesh::dump(const char *fname) const
|
nuclear@0
|
1016 {
|
nuclear@0
|
1017 FILE *fp = fopen(fname, "wb");
|
nuclear@0
|
1018 if(fp) {
|
nuclear@0
|
1019 bool res = dump(fp);
|
nuclear@0
|
1020 fclose(fp);
|
nuclear@0
|
1021 return res;
|
nuclear@0
|
1022 }
|
nuclear@0
|
1023 return false;
|
nuclear@0
|
1024 }
|
nuclear@0
|
1025
|
nuclear@0
|
1026 bool Mesh::dump(FILE *fp) const
|
nuclear@0
|
1027 {
|
nuclear@0
|
1028 if(!has_attrib(MESH_ATTR_VERTEX)) {
|
nuclear@0
|
1029 return false;
|
nuclear@0
|
1030 }
|
nuclear@0
|
1031
|
nuclear@0
|
1032 fprintf(fp, "VERTEX ATTRIBUTES\n");
|
nuclear@0
|
1033 static const char *label[] = { "pos", "nor", "tan", "tex", "col", "bw", "bid" };
|
nuclear@0
|
1034 static const char *elemfmt[] = { 0, " %s(%g)", " %s(%g, %g)", " %s(%g, %g, %g)", " %s(%g, %g, %g, %g)", 0 };
|
nuclear@0
|
1035
|
nuclear@0
|
1036 for(int i=0; i<(int)nverts; i++) {
|
nuclear@0
|
1037 fprintf(fp, "%5u:", i);
|
nuclear@0
|
1038 for(int j=0; j<NUM_MESH_ATTR; j++) {
|
nuclear@0
|
1039 if(has_attrib(j)) {
|
nuclear@0
|
1040 Vec4 v = get_attrib(j, i);
|
nuclear@0
|
1041 int nelem = vattr[j].nelem;
|
nuclear@0
|
1042 fprintf(fp, elemfmt[nelem], label[j], v.x, v.y, v.z, v.w);
|
nuclear@0
|
1043 }
|
nuclear@0
|
1044 }
|
nuclear@0
|
1045 fputc('\n', fp);
|
nuclear@0
|
1046 }
|
nuclear@0
|
1047
|
nuclear@0
|
1048 if(is_indexed()) {
|
nuclear@0
|
1049 const unsigned int *idx = get_index_data();
|
nuclear@0
|
1050 int numidx = get_index_count();
|
nuclear@0
|
1051 int numtri = numidx / 3;
|
nuclear@0
|
1052 assert(numidx % 3 == 0);
|
nuclear@0
|
1053
|
nuclear@0
|
1054 fprintf(fp, "FACES\n");
|
nuclear@0
|
1055
|
nuclear@0
|
1056 for(int i=0; i<numtri; i++) {
|
nuclear@0
|
1057 fprintf(fp, "%5d: %d %d %d\n", i, idx[0], idx[1], idx[2]);
|
nuclear@0
|
1058 idx += 3;
|
nuclear@0
|
1059 }
|
nuclear@0
|
1060 }
|
nuclear@0
|
1061 return true;
|
nuclear@0
|
1062 }
|
nuclear@0
|
1063
|
nuclear@0
|
1064 bool Mesh::dump_obj(const char *fname) const
|
nuclear@0
|
1065 {
|
nuclear@0
|
1066 FILE *fp = fopen(fname, "wb");
|
nuclear@0
|
1067 if(fp) {
|
nuclear@0
|
1068 bool res = dump_obj(fp);
|
nuclear@0
|
1069 fclose(fp);
|
nuclear@0
|
1070 return res;
|
nuclear@0
|
1071 }
|
nuclear@0
|
1072 return false;
|
nuclear@0
|
1073 }
|
nuclear@0
|
1074
|
nuclear@0
|
1075 bool Mesh::dump_obj(FILE *fp) const
|
nuclear@0
|
1076 {
|
nuclear@0
|
1077 if(!has_attrib(MESH_ATTR_VERTEX)) {
|
nuclear@0
|
1078 return false;
|
nuclear@0
|
1079 }
|
nuclear@0
|
1080
|
nuclear@0
|
1081 for(int i=0; i<(int)nverts; i++) {
|
nuclear@0
|
1082 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
|
nuclear@0
|
1083 fprintf(fp, "v %g %g %g\n", v.x, v.y, v.z);
|
nuclear@0
|
1084 }
|
nuclear@0
|
1085
|
nuclear@0
|
1086 if(has_attrib(MESH_ATTR_NORMAL)) {
|
nuclear@0
|
1087 for(int i=0; i<(int)nverts; i++) {
|
nuclear@0
|
1088 Vec4 v = get_attrib(MESH_ATTR_NORMAL, i);
|
nuclear@0
|
1089 fprintf(fp, "vn %g %g %g\n", v.x, v.y, v.z);
|
nuclear@0
|
1090 }
|
nuclear@0
|
1091 }
|
nuclear@0
|
1092
|
nuclear@0
|
1093 if(has_attrib(MESH_ATTR_TEXCOORD)) {
|
nuclear@0
|
1094 for(int i=0; i<(int)nverts; i++) {
|
nuclear@0
|
1095 Vec4 v = get_attrib(MESH_ATTR_TEXCOORD, i);
|
nuclear@0
|
1096 fprintf(fp, "vt %g %g\n", v.x, v.y);
|
nuclear@0
|
1097 }
|
nuclear@0
|
1098 }
|
nuclear@0
|
1099
|
nuclear@0
|
1100 if(is_indexed()) {
|
nuclear@0
|
1101 const unsigned int *idxptr = get_index_data();
|
nuclear@0
|
1102 int numidx = get_index_count();
|
nuclear@0
|
1103 int numtri = numidx / 3;
|
nuclear@0
|
1104 assert(numidx % 3 == 0);
|
nuclear@0
|
1105
|
nuclear@0
|
1106 for(int i=0; i<numtri; i++) {
|
nuclear@0
|
1107 fputc('f', fp);
|
nuclear@0
|
1108 for(int j=0; j<3; j++) {
|
nuclear@0
|
1109 unsigned int idx = *idxptr++ + 1;
|
nuclear@0
|
1110 fprintf(fp, " %u/%u/%u", idx, idx, idx);
|
nuclear@0
|
1111 }
|
nuclear@0
|
1112 fputc('\n', fp);
|
nuclear@0
|
1113 }
|
nuclear@0
|
1114 } else {
|
nuclear@0
|
1115 int numtri = nverts / 3;
|
nuclear@0
|
1116 unsigned int idx = 1;
|
nuclear@0
|
1117 for(int i=0; i<numtri; i++) {
|
nuclear@0
|
1118 fputc('f', fp);
|
nuclear@0
|
1119 for(int j=0; j<3; j++) {
|
nuclear@0
|
1120 fprintf(fp, " %u/%u/%u", idx, idx, idx);
|
nuclear@0
|
1121 ++idx;
|
nuclear@0
|
1122 }
|
nuclear@0
|
1123 fputc('\n', fp);
|
nuclear@0
|
1124 }
|
nuclear@0
|
1125 }
|
nuclear@0
|
1126 return true;
|
nuclear@0
|
1127 }
|
nuclear@0
|
1128
|
nuclear@0
|
1129 // ------ private member functions ------
|
nuclear@0
|
1130
|
nuclear@0
|
1131 void Mesh::calc_aabb()
|
nuclear@0
|
1132 {
|
nuclear@0
|
1133 // the cast is to force calling the const version which doesn't invalidate
|
nuclear@0
|
1134 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
|
nuclear@0
|
1135 return;
|
nuclear@0
|
1136 }
|
nuclear@0
|
1137
|
nuclear@0
|
1138 aabb.min = Vec3(FLT_MAX, FLT_MAX, FLT_MAX);
|
nuclear@0
|
1139 aabb.max = -aabb.min;
|
nuclear@0
|
1140
|
nuclear@0
|
1141 for(unsigned int i=0; i<nverts; i++) {
|
nuclear@0
|
1142 Vec4 v = get_attrib(MESH_ATTR_VERTEX, i);
|
nuclear@0
|
1143 for(int j=0; j<3; j++) {
|
nuclear@0
|
1144 if(v[j] < aabb.min[j]) {
|
nuclear@0
|
1145 aabb.min[j] = v[j];
|
nuclear@0
|
1146 }
|
nuclear@0
|
1147 if(v[j] > aabb.max[j]) {
|
nuclear@0
|
1148 aabb.max[j] = v[j];
|
nuclear@0
|
1149 }
|
nuclear@0
|
1150 }
|
nuclear@0
|
1151 }
|
nuclear@0
|
1152 aabb_valid = true;
|
nuclear@0
|
1153 }
|
nuclear@0
|
1154
|
nuclear@0
|
1155 void Mesh::calc_bsph()
|
nuclear@0
|
1156 {
|
nuclear@0
|
1157 // the cast is to force calling the const version which doesn't invalidate
|
nuclear@0
|
1158 if(!((const Mesh*)this)->get_attrib_data(MESH_ATTR_VERTEX)) {
|
nuclear@0
|
1159 return;
|
nuclear@0
|
1160 }
|
nuclear@0
|
1161
|
nuclear@0
|
1162 Vec3 v;
|
nuclear@0
|
1163 bsph.center = Vec3(0, 0, 0);
|
nuclear@0
|
1164
|
nuclear@0
|
1165 // first find the center
|
nuclear@0
|
1166 for(unsigned int i=0; i<nverts; i++) {
|
nuclear@0
|
1167 v = get_attrib(MESH_ATTR_VERTEX, i).xyz();
|
nuclear@0
|
1168 bsph.center += v;
|
nuclear@0
|
1169 }
|
nuclear@0
|
1170 bsph.center /= (float)nverts;
|
nuclear@0
|
1171
|
nuclear@0
|
1172 bsph.radius = 0.0f;
|
nuclear@0
|
1173 for(unsigned int i=0; i<nverts; i++) {
|
nuclear@0
|
1174 v = get_attrib(MESH_ATTR_VERTEX, i).xyz();
|
nuclear@0
|
1175 float dist_sq = length_sq(v - bsph.center);
|
nuclear@0
|
1176 if(dist_sq > bsph.radius) {
|
nuclear@0
|
1177 bsph.radius = dist_sq;
|
nuclear@0
|
1178 }
|
nuclear@0
|
1179 }
|
nuclear@0
|
1180 bsph.radius = sqrt(bsph.radius);
|
nuclear@0
|
1181
|
nuclear@0
|
1182 bsph_valid = true;
|
nuclear@0
|
1183 }
|
nuclear@0
|
1184
|
nuclear@0
|
1185 void Mesh::update_buffers()
|
nuclear@0
|
1186 {
|
nuclear@0
|
1187 for(int i=0; i<NUM_MESH_ATTR; i++) {
|
nuclear@0
|
1188 if(has_attrib(i) && !vattr[i].vbo_valid) {
|
nuclear@0
|
1189 glBindBuffer(GL_ARRAY_BUFFER, vattr[i].vbo);
|
nuclear@0
|
1190 glBufferData(GL_ARRAY_BUFFER, nverts * vattr[i].nelem * sizeof(float), &vattr[i].data[0], GL_STATIC_DRAW);
|
nuclear@0
|
1191 vattr[i].vbo_valid = true;
|
nuclear@0
|
1192 }
|
nuclear@0
|
1193 }
|
nuclear@0
|
1194 glBindBuffer(GL_ARRAY_BUFFER, 0);
|
nuclear@0
|
1195
|
nuclear@0
|
1196 if(idata_valid && !ibo_valid) {
|
nuclear@0
|
1197 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
nuclear@0
|
1198 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 3 * sizeof(unsigned int), &idata[0], GL_STATIC_DRAW);
|
nuclear@0
|
1199 ibo_valid = true;
|
nuclear@0
|
1200 }
|
nuclear@0
|
1201 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
nuclear@0
|
1202 }
|
nuclear@0
|
1203
|
nuclear@0
|
1204 void Mesh::update_wire_ibo()
|
nuclear@0
|
1205 {
|
nuclear@0
|
1206 update_buffers();
|
nuclear@0
|
1207
|
nuclear@0
|
1208 if(wire_ibo_valid) {
|
nuclear@0
|
1209 return;
|
nuclear@0
|
1210 }
|
nuclear@0
|
1211
|
nuclear@0
|
1212 if(!wire_ibo) {
|
nuclear@0
|
1213 glGenBuffers(1, &wire_ibo);
|
nuclear@0
|
1214 }
|
nuclear@0
|
1215
|
nuclear@0
|
1216 unsigned int *wire_idxarr = new unsigned int[nfaces * 6];
|
nuclear@0
|
1217 unsigned int *dest = wire_idxarr;
|
nuclear@0
|
1218
|
nuclear@0
|
1219 if(ibo_valid) {
|
nuclear@0
|
1220 // we're dealing with an indexed mesh
|
nuclear@0
|
1221 const unsigned int *idxarr = ((const Mesh*)this)->get_index_data();
|
nuclear@0
|
1222
|
nuclear@0
|
1223 for(unsigned int i=0; i<nfaces; i++) {
|
nuclear@0
|
1224 *dest++ = idxarr[0];
|
nuclear@0
|
1225 *dest++ = idxarr[1];
|
nuclear@0
|
1226 *dest++ = idxarr[1];
|
nuclear@0
|
1227 *dest++ = idxarr[2];
|
nuclear@0
|
1228 *dest++ = idxarr[2];
|
nuclear@0
|
1229 *dest++ = idxarr[0];
|
nuclear@0
|
1230 idxarr += 3;
|
nuclear@0
|
1231 }
|
nuclear@0
|
1232 } else {
|
nuclear@0
|
1233 // not an indexed mesh ...
|
nuclear@0
|
1234 for(unsigned int i=0; i<nfaces; i++) {
|
nuclear@0
|
1235 int vidx = i * 3;
|
nuclear@0
|
1236 *dest++ = vidx;
|
nuclear@0
|
1237 *dest++ = vidx + 1;
|
nuclear@0
|
1238 *dest++ = vidx + 1;
|
nuclear@0
|
1239 *dest++ = vidx + 2;
|
nuclear@0
|
1240 *dest++ = vidx + 2;
|
nuclear@0
|
1241 *dest++ = vidx;
|
nuclear@0
|
1242 }
|
nuclear@0
|
1243 }
|
nuclear@0
|
1244
|
nuclear@0
|
1245 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, wire_ibo);
|
nuclear@0
|
1246 glBufferData(GL_ELEMENT_ARRAY_BUFFER, nfaces * 6 * sizeof(unsigned int), wire_idxarr, GL_STATIC_DRAW);
|
nuclear@0
|
1247 delete [] wire_idxarr;
|
nuclear@0
|
1248 wire_ibo_valid = true;
|
nuclear@0
|
1249 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
nuclear@0
|
1250 }
|
nuclear@0
|
1251
|
nuclear@0
|
1252
|
nuclear@0
|
1253 // ------ class Triangle ------
|
nuclear@0
|
1254 Triangle::Triangle()
|
nuclear@0
|
1255 {
|
nuclear@0
|
1256 normal_valid = false;
|
nuclear@0
|
1257 id = -1;
|
nuclear@0
|
1258 }
|
nuclear@0
|
1259
|
nuclear@0
|
1260 Triangle::Triangle(const Vec3 &v0, const Vec3 &v1, const Vec3 &v2)
|
nuclear@0
|
1261 {
|
nuclear@0
|
1262 v[0] = v0;
|
nuclear@0
|
1263 v[1] = v1;
|
nuclear@0
|
1264 v[2] = v2;
|
nuclear@0
|
1265 normal_valid = false;
|
nuclear@0
|
1266 id = -1;
|
nuclear@0
|
1267 }
|
nuclear@0
|
1268
|
nuclear@0
|
1269 Triangle::Triangle(int n, const Vec3 *varr, const unsigned int *idxarr)
|
nuclear@0
|
1270 {
|
nuclear@0
|
1271 if(idxarr) {
|
nuclear@0
|
1272 v[0] = varr[idxarr[n * 3]];
|
nuclear@0
|
1273 v[1] = varr[idxarr[n * 3 + 1]];
|
nuclear@0
|
1274 v[2] = varr[idxarr[n * 3 + 2]];
|
nuclear@0
|
1275 } else {
|
nuclear@0
|
1276 v[0] = varr[n * 3];
|
nuclear@0
|
1277 v[1] = varr[n * 3 + 1];
|
nuclear@0
|
1278 v[2] = varr[n * 3 + 2];
|
nuclear@0
|
1279 }
|
nuclear@0
|
1280 normal_valid = false;
|
nuclear@0
|
1281 id = n;
|
nuclear@0
|
1282 }
|
nuclear@0
|
1283
|
nuclear@0
|
1284 void Triangle::calc_normal()
|
nuclear@0
|
1285 {
|
nuclear@0
|
1286 normal = normalize(cross(v[1] - v[0], v[2] - v[0]));
|
nuclear@0
|
1287 normal_valid = true;
|
nuclear@0
|
1288 }
|
nuclear@0
|
1289
|
nuclear@0
|
1290 const Vec3 &Triangle::get_normal() const
|
nuclear@0
|
1291 {
|
nuclear@0
|
1292 if(!normal_valid) {
|
nuclear@0
|
1293 ((Triangle*)this)->calc_normal();
|
nuclear@0
|
1294 }
|
nuclear@0
|
1295 return normal;
|
nuclear@0
|
1296 }
|
nuclear@0
|
1297
|
nuclear@0
|
1298 void Triangle::transform(const Mat4 &xform)
|
nuclear@0
|
1299 {
|
nuclear@0
|
1300 v[0] = xform * v[0];
|
nuclear@0
|
1301 v[1] = xform * v[1];
|
nuclear@0
|
1302 v[2] = xform * v[2];
|
nuclear@0
|
1303 normal_valid = false;
|
nuclear@0
|
1304 }
|
nuclear@0
|
1305
|
nuclear@0
|
1306 void Triangle::draw() const
|
nuclear@0
|
1307 {
|
nuclear@0
|
1308 Vec3 n[3];
|
nuclear@0
|
1309 n[0] = n[1] = n[2] = get_normal();
|
nuclear@0
|
1310
|
nuclear@0
|
1311 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
|
nuclear@0
|
1312 int nloc = Mesh::get_attrib_location(MESH_ATTR_NORMAL);
|
nuclear@0
|
1313
|
nuclear@0
|
1314 glEnableVertexAttribArray(vloc);
|
nuclear@0
|
1315 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
|
nuclear@0
|
1316 glVertexAttribPointer(nloc, 3, GL_FLOAT, GL_FALSE, 0, &n[0].x);
|
nuclear@0
|
1317
|
nuclear@0
|
1318 glDrawArrays(GL_TRIANGLES, 0, 3);
|
nuclear@0
|
1319
|
nuclear@0
|
1320 glDisableVertexAttribArray(vloc);
|
nuclear@0
|
1321 glDisableVertexAttribArray(nloc);
|
nuclear@0
|
1322 }
|
nuclear@0
|
1323
|
nuclear@0
|
1324 void Triangle::draw_wire() const
|
nuclear@0
|
1325 {
|
nuclear@0
|
1326 static const int idxarr[] = {0, 1, 1, 2, 2, 0};
|
nuclear@0
|
1327 int vloc = Mesh::get_attrib_location(MESH_ATTR_VERTEX);
|
nuclear@0
|
1328
|
nuclear@0
|
1329 glEnableVertexAttribArray(vloc);
|
nuclear@0
|
1330 glVertexAttribPointer(vloc, 3, GL_FLOAT, GL_FALSE, 0, &v[0].x);
|
nuclear@0
|
1331
|
nuclear@0
|
1332 glDrawElements(GL_LINES, 6, GL_UNSIGNED_INT, idxarr);
|
nuclear@0
|
1333
|
nuclear@0
|
1334 glDisableVertexAttribArray(vloc);
|
nuclear@0
|
1335 }
|
nuclear@0
|
1336
|
nuclear@0
|
1337 Vec3 Triangle::calc_barycentric(const Vec3 &pos) const
|
nuclear@0
|
1338 {
|
nuclear@0
|
1339 Vec3 norm = get_normal();
|
nuclear@0
|
1340
|
nuclear@0
|
1341 float area_sq = fabs(dot(cross(v[1] - v[0], v[2] - v[0]), norm));
|
nuclear@0
|
1342 if(area_sq < 1e-5) {
|
nuclear@0
|
1343 return Vec3(0, 0, 0);
|
nuclear@0
|
1344 }
|
nuclear@0
|
1345
|
nuclear@0
|
1346 float asq0 = fabs(dot(cross(v[1] - pos, v[2] - pos), norm));
|
nuclear@0
|
1347 float asq1 = fabs(dot(cross(v[2] - pos, v[0] - pos), norm));
|
nuclear@0
|
1348 float asq2 = fabs(dot(cross(v[0] - pos, v[1] - pos), norm));
|
nuclear@0
|
1349
|
nuclear@0
|
1350 return Vec3(asq0 / area_sq, asq1 / area_sq, asq2 / area_sq);
|
nuclear@0
|
1351 }
|
nuclear@0
|
1352
|
nuclear@0
|
1353 bool Triangle::intersect(const Ray &ray, HitPoint *hit) const
|
nuclear@0
|
1354 {
|
nuclear@0
|
1355 Vec3 normal = get_normal();
|
nuclear@0
|
1356
|
nuclear@0
|
1357 float ndotdir = dot(ray.dir, normal);
|
nuclear@0
|
1358 if(fabs(ndotdir) < 1e-4) {
|
nuclear@0
|
1359 return false;
|
nuclear@0
|
1360 }
|
nuclear@0
|
1361
|
nuclear@0
|
1362 Vec3 vertdir = v[0] - ray.origin;
|
nuclear@0
|
1363 float t = dot(normal, vertdir) / ndotdir;
|
nuclear@0
|
1364
|
nuclear@0
|
1365 Vec3 pos = ray.origin + ray.dir * t;
|
nuclear@0
|
1366 Vec3 bary = calc_barycentric(pos);
|
nuclear@0
|
1367
|
nuclear@0
|
1368 if(bary.x + bary.y + bary.z > 1.00001) {
|
nuclear@0
|
1369 return false;
|
nuclear@0
|
1370 }
|
nuclear@0
|
1371
|
nuclear@0
|
1372 if(hit) {
|
nuclear@0
|
1373 hit->dist = t;
|
nuclear@0
|
1374 hit->pos = ray.origin + ray.dir * t;
|
nuclear@0
|
1375 hit->normal = normal;
|
nuclear@0
|
1376 hit->obj = this;
|
nuclear@0
|
1377 }
|
nuclear@0
|
1378 return true;
|
nuclear@0
|
1379 }
|