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