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