vrheights

annotate src/mesh.cc @ 14:25cab9e20c9c

mesh vbos
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 09 Oct 2014 01:29:28 +0300
parents 3f221bdc9bab
children
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 }