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