rev |
line source |
nuclear@8
|
1 #include <string.h>
|
nuclear@8
|
2 #include "mesh.h"
|
nuclear@8
|
3 #include "opengl.h"
|
nuclear@8
|
4
|
nuclear@8
|
5 Mesh::Mesh()
|
nuclear@8
|
6 {
|
nuclear@8
|
7 set_primitive(GL_TRIANGLES);
|
nuclear@8
|
8
|
nuclear@8
|
9 for(int i=0; i<NUM_MESH_ATTRIBS; i++) {
|
nuclear@8
|
10 attrib[i].nelems = 3;
|
nuclear@8
|
11 attrib[i].sdrloc = -1;
|
nuclear@8
|
12 attrib[i].vbo = 0;
|
nuclear@8
|
13 attrib[i].vbo_valid = false;
|
nuclear@8
|
14 }
|
nuclear@8
|
15 num_verts = 0;
|
nuclear@8
|
16
|
nuclear@8
|
17 num_idx = 0;
|
nuclear@8
|
18 ibo = 0;
|
nuclear@8
|
19 ibo_size = 0;
|
nuclear@8
|
20 ibo_valid = false;
|
nuclear@8
|
21
|
nuclear@8
|
22 vbo_usage = ibo_usage = GL_STATIC_DRAW;
|
nuclear@8
|
23 }
|
nuclear@8
|
24
|
nuclear@8
|
25 Mesh::~Mesh()
|
nuclear@8
|
26 {
|
nuclear@8
|
27 clear();
|
nuclear@8
|
28
|
nuclear@8
|
29 for(int i=0; i<NUM_MESH_ATTRIBS; i++) {
|
nuclear@8
|
30 if(attrib[i].vbo) {
|
nuclear@8
|
31 glDeleteBuffers(1, &attrib[i].vbo);
|
nuclear@8
|
32 }
|
nuclear@8
|
33 }
|
nuclear@8
|
34 if(ibo) {
|
nuclear@8
|
35 glDeleteBuffers(1, &ibo);
|
nuclear@8
|
36 }
|
nuclear@8
|
37 }
|
nuclear@8
|
38
|
nuclear@8
|
39 void Mesh::clear()
|
nuclear@8
|
40 {
|
nuclear@8
|
41 for(int i=0; i<NUM_MESH_ATTRIBS; i++) {
|
nuclear@8
|
42 attrib[i].vbo_valid = false;
|
nuclear@8
|
43 attrib[i].data.clear();
|
nuclear@8
|
44
|
nuclear@8
|
45 }
|
nuclear@8
|
46 ibo_valid = false;
|
nuclear@8
|
47 index.clear();
|
nuclear@8
|
48 }
|
nuclear@8
|
49
|
nuclear@8
|
50 void Mesh::set_primitive(int prim)
|
nuclear@8
|
51 {
|
nuclear@8
|
52 if(prim == -1) {
|
nuclear@8
|
53 this->prim = GL_TRIANGLES;
|
nuclear@8
|
54 } else {
|
nuclear@8
|
55 this->prim = prim;
|
nuclear@8
|
56 }
|
nuclear@8
|
57
|
nuclear@8
|
58 switch(this->prim) {
|
nuclear@8
|
59 case GL_TRIANGLES:
|
nuclear@8
|
60 prim_verts = 3;
|
nuclear@8
|
61 break;
|
nuclear@8
|
62
|
nuclear@8
|
63 case GL_QUADS:
|
nuclear@8
|
64 prim_verts = 4;
|
nuclear@8
|
65 break;
|
nuclear@8
|
66
|
nuclear@8
|
67 case GL_LINES:
|
nuclear@8
|
68 prim_verts = 2;
|
nuclear@8
|
69 break;
|
nuclear@8
|
70
|
nuclear@8
|
71 case GL_POINTS:
|
nuclear@8
|
72 prim_verts = 1;
|
nuclear@8
|
73 break;
|
nuclear@8
|
74
|
nuclear@8
|
75 default:
|
nuclear@8
|
76 break;
|
nuclear@8
|
77 }
|
nuclear@8
|
78 }
|
nuclear@8
|
79
|
nuclear@8
|
80 void Mesh::set_attrib_location(int attr, int loc)
|
nuclear@8
|
81 {
|
nuclear@8
|
82 attrib[attr].sdrloc = loc;
|
nuclear@8
|
83 }
|
nuclear@8
|
84
|
nuclear@8
|
85 float *Mesh::set_vertex_data(int attr, int nelem, int count, float *data)
|
nuclear@8
|
86 {
|
nuclear@8
|
87 attrib[attr].data.resize(count * nelem);
|
nuclear@8
|
88 if(data) {
|
nuclear@8
|
89 memcpy(&attrib[attr].data[0], data, nelem * count * sizeof(float));
|
nuclear@8
|
90 }
|
nuclear@8
|
91
|
nuclear@8
|
92 attrib[attr].nelems = nelem;
|
nuclear@8
|
93 attrib[attr].vbo_valid = false;
|
nuclear@8
|
94
|
nuclear@8
|
95 num_verts = count;
|
nuclear@8
|
96
|
nuclear@8
|
97 return &attrib[attr].data[0];
|
nuclear@8
|
98 }
|
nuclear@8
|
99
|
nuclear@8
|
100 unsigned int *Mesh::set_index_data(int count, unsigned int *data)
|
nuclear@8
|
101 {
|
nuclear@8
|
102 index.resize(count);
|
nuclear@8
|
103 if(data) {
|
nuclear@8
|
104 memcpy(&index[0], data, count * sizeof(unsigned int));
|
nuclear@8
|
105 }
|
nuclear@8
|
106
|
nuclear@8
|
107 num_idx = count;
|
nuclear@8
|
108 ibo_valid = false;
|
nuclear@8
|
109
|
nuclear@8
|
110 return &index[0];
|
nuclear@8
|
111 }
|
nuclear@8
|
112
|
nuclear@8
|
113 int Mesh::get_vertex_count() const
|
nuclear@8
|
114 {
|
nuclear@8
|
115 return num_verts;
|
nuclear@8
|
116 }
|
nuclear@8
|
117
|
nuclear@8
|
118 float *Mesh::get_vertex_data(int attr)
|
nuclear@8
|
119 {
|
nuclear@8
|
120 if(attrib[attr].data.empty()) {
|
nuclear@8
|
121 return 0;
|
nuclear@8
|
122 }
|
nuclear@8
|
123 return &attrib[attr].data[0];
|
nuclear@8
|
124 }
|
nuclear@8
|
125
|
nuclear@8
|
126 const float *Mesh::get_vertex_data(int attr) const
|
nuclear@8
|
127 {
|
nuclear@8
|
128 if(attrib[attr].data.empty()) {
|
nuclear@8
|
129 return 0;
|
nuclear@8
|
130 }
|
nuclear@8
|
131 return &attrib[attr].data[0];
|
nuclear@8
|
132 }
|
nuclear@8
|
133
|
nuclear@8
|
134 int Mesh::get_index_count() const
|
nuclear@8
|
135 {
|
nuclear@8
|
136 return num_idx;
|
nuclear@8
|
137 }
|
nuclear@8
|
138
|
nuclear@8
|
139 unsigned int *Mesh::get_index_data()
|
nuclear@8
|
140 {
|
nuclear@8
|
141 if(index.empty()) {
|
nuclear@8
|
142 return 0;
|
nuclear@8
|
143 }
|
nuclear@8
|
144 return &index[0];
|
nuclear@8
|
145 }
|
nuclear@8
|
146
|
nuclear@8
|
147 const unsigned int *Mesh::get_index_data() const
|
nuclear@8
|
148 {
|
nuclear@8
|
149 if(index.empty()) {
|
nuclear@8
|
150 return 0;
|
nuclear@8
|
151 }
|
nuclear@8
|
152 return &index[0];
|
nuclear@8
|
153 }
|
nuclear@8
|
154
|
nuclear@8
|
155 int Mesh::get_face_count() const
|
nuclear@8
|
156 {
|
nuclear@8
|
157 if(index.empty()) {
|
nuclear@8
|
158 return get_vertex_count() / prim_verts;
|
nuclear@8
|
159 }
|
nuclear@8
|
160 return get_index_count() / prim_verts;
|
nuclear@8
|
161 }
|
nuclear@8
|
162
|
nuclear@8
|
163 MeshFace Mesh::get_face(int idx) const
|
nuclear@8
|
164 {
|
nuclear@8
|
165 MeshFace face;
|
nuclear@8
|
166 face.vcount = prim_verts;
|
nuclear@8
|
167
|
nuclear@8
|
168 int nfaces = get_face_count();
|
nuclear@8
|
169 if(idx < 0 || idx >= nfaces) {
|
nuclear@8
|
170 return face;
|
nuclear@8
|
171 }
|
nuclear@8
|
172
|
nuclear@8
|
173 const Vector3 *verts = (const Vector3*)&attrib[MESH_VERTEX].data[0];
|
nuclear@8
|
174
|
nuclear@8
|
175 if(index.empty()) {
|
nuclear@8
|
176 for(int i=0; i<3; i++) {
|
nuclear@8
|
177 face.v[i] = verts[idx * 3 + i];
|
nuclear@8
|
178 }
|
nuclear@8
|
179
|
nuclear@8
|
180 } else {
|
nuclear@8
|
181 for(int i=0; i<3; i++) {
|
nuclear@8
|
182 int vidx = index[idx * 3 + i];
|
nuclear@8
|
183 face.v[i] = verts[vidx];
|
nuclear@8
|
184 }
|
nuclear@8
|
185 }
|
nuclear@8
|
186
|
nuclear@8
|
187 return face;
|
nuclear@8
|
188 }
|
nuclear@8
|
189
|
nuclear@8
|
190
|
nuclear@8
|
191 void Mesh::begin(int prim)
|
nuclear@8
|
192 {
|
nuclear@8
|
193 if(prim == -1) {
|
nuclear@8
|
194 this->prim = GL_TRIANGLES;
|
nuclear@8
|
195 } else {
|
nuclear@8
|
196 this->prim = prim;
|
nuclear@8
|
197 }
|
nuclear@8
|
198
|
nuclear@8
|
199 clear();
|
nuclear@8
|
200
|
nuclear@8
|
201 cur_norm_valid = false;
|
nuclear@8
|
202 cur_tc_valid = false;
|
nuclear@8
|
203 cur_tang_valid = false;
|
nuclear@8
|
204 }
|
nuclear@8
|
205
|
nuclear@8
|
206 void Mesh::end()
|
nuclear@8
|
207 {
|
nuclear@8
|
208 }
|
nuclear@8
|
209
|
nuclear@8
|
210 void Mesh::vertex(float x, float y, float z)
|
nuclear@8
|
211 {
|
nuclear@8
|
212 if(cur_norm_valid) {
|
nuclear@8
|
213 attrib[MESH_NORMAL].data.push_back(cur_norm.x);
|
nuclear@8
|
214 attrib[MESH_NORMAL].data.push_back(cur_norm.y);
|
nuclear@8
|
215 attrib[MESH_NORMAL].data.push_back(cur_norm.z);
|
nuclear@8
|
216 }
|
nuclear@8
|
217 if(cur_tc_valid) {
|
nuclear@8
|
218 attrib[MESH_TEXCOORD].data.push_back(cur_tc.x);
|
nuclear@8
|
219 attrib[MESH_TEXCOORD].data.push_back(cur_tc.y);
|
nuclear@8
|
220 }
|
nuclear@8
|
221 if(cur_tang_valid) {
|
nuclear@8
|
222 attrib[MESH_TANGENT].data.push_back(cur_tang.x);
|
nuclear@8
|
223 attrib[MESH_TANGENT].data.push_back(cur_tang.y);
|
nuclear@8
|
224 attrib[MESH_TANGENT].data.push_back(cur_tang.z);
|
nuclear@8
|
225 }
|
nuclear@8
|
226 attrib[MESH_VERTEX].data.push_back(x);
|
nuclear@8
|
227 attrib[MESH_VERTEX].data.push_back(y);
|
nuclear@8
|
228 attrib[MESH_VERTEX].data.push_back(z);
|
nuclear@8
|
229 }
|
nuclear@8
|
230
|
nuclear@8
|
231 void Mesh::normal(float x, float y, float z)
|
nuclear@8
|
232 {
|
nuclear@8
|
233 cur_norm = Vector3(x, y, z);
|
nuclear@8
|
234 cur_norm_valid = true;
|
nuclear@8
|
235 }
|
nuclear@8
|
236
|
nuclear@8
|
237 void Mesh::texcoord(float x, float y)
|
nuclear@8
|
238 {
|
nuclear@8
|
239 cur_tc = Vector2(x, y);
|
nuclear@8
|
240 cur_tc_valid = true;
|
nuclear@8
|
241 }
|
nuclear@8
|
242
|
nuclear@8
|
243 void Mesh::tangent(float x, float y, float z)
|
nuclear@8
|
244 {
|
nuclear@8
|
245 cur_tang = Vector3(x, y, z);
|
nuclear@8
|
246 cur_tang_valid = true;
|
nuclear@8
|
247 }
|
nuclear@8
|
248
|
nuclear@14
|
249 void Mesh::update_buffers()
|
nuclear@14
|
250 {
|
nuclear@14
|
251 for(int i=0; i<NUM_MESH_ATTRIBS; i++) {
|
nuclear@14
|
252 if(attrib[i].vbo_valid || attrib[i].data.empty()) {
|
nuclear@14
|
253 continue;
|
nuclear@14
|
254 }
|
nuclear@14
|
255 int count = (int)attrib[i].data.size();
|
nuclear@14
|
256
|
nuclear@14
|
257 float *ptr = &attrib[i].data[0];
|
nuclear@14
|
258 // TODO: check previous size and don't resize if it's not needed
|
nuclear@14
|
259 attrib[i].vbo_size = count * attrib[i].nelems * sizeof(float);
|
nuclear@14
|
260
|
nuclear@14
|
261 if(!attrib[i].vbo) {
|
nuclear@14
|
262 glGenBuffers(1, &attrib[i].vbo);
|
nuclear@14
|
263 }
|
nuclear@14
|
264
|
nuclear@14
|
265 glBindBuffer(GL_ARRAY_BUFFER, attrib[i].vbo);
|
nuclear@14
|
266 glBufferData(GL_ARRAY_BUFFER, attrib[i].vbo_size, ptr, vbo_usage);
|
nuclear@14
|
267 attrib[i].vbo_valid = true;
|
nuclear@14
|
268 }
|
nuclear@14
|
269
|
nuclear@14
|
270 if(!ibo_valid && !index.empty()) {
|
nuclear@14
|
271 unsigned int *ptr = &index[0];
|
nuclear@14
|
272 ibo_size = index.size() * sizeof *ptr; // TODO: see above
|
nuclear@14
|
273
|
nuclear@14
|
274 if(!ibo) {
|
nuclear@14
|
275 glGenBuffers(1, &ibo);
|
nuclear@14
|
276 }
|
nuclear@14
|
277
|
nuclear@14
|
278 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
nuclear@14
|
279 glBufferData(GL_ELEMENT_ARRAY_BUFFER, ibo_size, ptr, ibo_usage);
|
nuclear@14
|
280 ibo_valid = true;
|
nuclear@14
|
281 }
|
nuclear@14
|
282 }
|
nuclear@14
|
283
|
nuclear@8
|
284 void Mesh::draw() const
|
nuclear@8
|
285 {
|
nuclear@8
|
286 if(attrib[MESH_VERTEX].data.empty()) {
|
nuclear@8
|
287 return;
|
nuclear@8
|
288 }
|
nuclear@8
|
289
|
nuclear@14
|
290 ((Mesh*)this)->update_buffers();
|
nuclear@14
|
291
|
nuclear@8
|
292 bool use_norm = !attrib[MESH_NORMAL].data.empty();
|
nuclear@8
|
293 bool use_tc = !attrib[MESH_TEXCOORD].data.empty();
|
nuclear@8
|
294 bool use_tang = !attrib[MESH_TANGENT].data.empty();
|
nuclear@8
|
295 int norm_loc, tc_loc, tang_loc;
|
nuclear@8
|
296
|
nuclear@14
|
297 glBindBuffer(GL_ARRAY_BUFFER, attrib[MESH_VERTEX].vbo);
|
nuclear@8
|
298 int loc = attrib[MESH_VERTEX].sdrloc;
|
nuclear@8
|
299 if(loc == -1) {
|
nuclear@8
|
300 glEnableClientState(GL_VERTEX_ARRAY);
|
nuclear@14
|
301 glVertexPointer(attrib[MESH_VERTEX].nelems, GL_FLOAT, 0, 0);
|
nuclear@8
|
302 } else {
|
nuclear@8
|
303 glEnableVertexAttribArray(loc);
|
nuclear@14
|
304 glVertexAttribPointer(loc, attrib[MESH_VERTEX].nelems, GL_FLOAT, 0, 0, 0);
|
nuclear@8
|
305 }
|
nuclear@8
|
306
|
nuclear@8
|
307 if(use_norm) {
|
nuclear@14
|
308 glBindBuffer(GL_ARRAY_BUFFER, attrib[MESH_NORMAL].vbo);
|
nuclear@8
|
309 norm_loc = attrib[MESH_NORMAL].sdrloc;
|
nuclear@8
|
310 if(norm_loc == -1) {
|
nuclear@8
|
311 glEnableClientState(GL_NORMAL_ARRAY);
|
nuclear@14
|
312 glNormalPointer(GL_FLOAT, 0, 0);
|
nuclear@8
|
313 } else {
|
nuclear@8
|
314 glEnableVertexAttribArray(norm_loc);
|
nuclear@14
|
315 glVertexAttribPointer(norm_loc, attrib[MESH_NORMAL].nelems, GL_FLOAT, 0, 0, 0);
|
nuclear@8
|
316 }
|
nuclear@8
|
317 }
|
nuclear@8
|
318
|
nuclear@8
|
319 if(use_tc) {
|
nuclear@14
|
320 glBindBuffer(GL_ARRAY_BUFFER, attrib[MESH_TEXCOORD].vbo);
|
nuclear@8
|
321 tc_loc = attrib[MESH_TEXCOORD].sdrloc;
|
nuclear@8
|
322 if(tc_loc == -1) {
|
nuclear@8
|
323 glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
nuclear@14
|
324 glTexCoordPointer(attrib[MESH_TEXCOORD].nelems, GL_FLOAT, 0, 0);
|
nuclear@8
|
325 } else {
|
nuclear@8
|
326 glEnableVertexAttribArray(tc_loc);
|
nuclear@14
|
327 glVertexAttribPointer(tc_loc, attrib[MESH_TEXCOORD].nelems, GL_FLOAT, 0, 0, 0);
|
nuclear@8
|
328 }
|
nuclear@8
|
329 }
|
nuclear@8
|
330
|
nuclear@8
|
331 if(!attrib[MESH_TANGENT].data.empty()) {
|
nuclear@14
|
332 glBindBuffer(GL_ARRAY_BUFFER, attrib[MESH_TANGENT].vbo);
|
nuclear@8
|
333 tang_loc = attrib[MESH_TANGENT].sdrloc;
|
nuclear@8
|
334 if(tang_loc != -1) {
|
nuclear@8
|
335 glEnableVertexAttribArray(tang_loc);
|
nuclear@14
|
336 glVertexAttribPointer(tang_loc, attrib[MESH_TANGENT].nelems, GL_FLOAT, 0, 0, 0);
|
nuclear@8
|
337 }
|
nuclear@8
|
338 }
|
nuclear@8
|
339
|
nuclear@14
|
340 glBindBuffer(GL_ARRAY_BUFFER, 0);
|
nuclear@14
|
341
|
nuclear@8
|
342 if(!index.empty()) {
|
nuclear@14
|
343 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
|
nuclear@14
|
344 glDrawElements(prim, num_idx, GL_UNSIGNED_INT, 0);
|
nuclear@14
|
345 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
nuclear@8
|
346 } else {
|
nuclear@8
|
347 glDrawArrays(prim, 0, num_verts * 3);
|
nuclear@8
|
348 }
|
nuclear@8
|
349
|
nuclear@8
|
350 if(use_norm) {
|
nuclear@8
|
351 if(norm_loc == -1) {
|
nuclear@8
|
352 glDisableClientState(GL_NORMAL_ARRAY);
|
nuclear@8
|
353 } else {
|
nuclear@8
|
354 glDisableVertexAttribArray(norm_loc);
|
nuclear@8
|
355 }
|
nuclear@8
|
356 }
|
nuclear@8
|
357 if(use_tc) {
|
nuclear@8
|
358 if(tc_loc == -1) {
|
nuclear@8
|
359 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
nuclear@8
|
360 } else {
|
nuclear@8
|
361 glDisableVertexAttribArray(tc_loc);
|
nuclear@8
|
362 }
|
nuclear@8
|
363 }
|
nuclear@8
|
364 if(use_tang) {
|
nuclear@8
|
365 if(tang_loc != -1) {
|
nuclear@8
|
366 glDisableVertexAttribArray(tang_loc);
|
nuclear@8
|
367 }
|
nuclear@8
|
368 }
|
nuclear@8
|
369 }
|