1 struct vertmodel : animmodel 2 { 3 struct vert { vec norm, pos; }; 4 struct vvertff { vec pos; float u, v; }; 5 struct vvert : vvertff { vec norm; }; 6 struct vvertbump : vvert { vec tangent; float bitangent; }; 7 struct tcvert { float u, v; }; 8 struct bumpvert { vec tangent; float bitangent; }; 9 struct tri { ushort vert[3]; }; 10 11 struct vbocacheentry 12 { 13 uchar *vdata; 14 GLuint vbuf; 15 animstate as; 16 int millis; 17 vbocacheentryvertmodel::vbocacheentry18 vbocacheentry() : vdata(NULL), vbuf(0) { as.cur.fr1 = as.prev.fr1 = -1; } 19 }; 20 21 struct vertmesh : mesh 22 { 23 vert *verts; 24 tcvert *tcverts; 25 bumpvert *bumpverts; 26 tri *tris; 27 int numverts, numtris; 28 29 int voffset, eoffset, elen; 30 ushort minvert, maxvert; 31 vertmeshvertmodel::vertmesh32 vertmesh() : verts(0), tcverts(0), bumpverts(0), tris(0) 33 { 34 } 35 ~vertmeshvertmodel::vertmesh36 virtual ~vertmesh() 37 { 38 DELETEA(verts); 39 DELETEA(tcverts); 40 DELETEA(bumpverts); 41 DELETEA(tris); 42 } 43 44 void buildnorms(bool areaweight = true) 45 { 46 loopk(((vertmeshgroup *)group)->numframes) 47 { 48 vert *fverts = &verts[k*numverts]; 49 loopi(numverts) fverts[i].norm = vec(0, 0, 0); loopivertmodel::vertmesh50 loopi(numtris) 51 { 52 tri &t = tris[i]; 53 vert &v1 = fverts[t.vert[0]], &v2 = fverts[t.vert[1]], &v3 = fverts[t.vert[2]]; 54 vec norm; 55 norm.cross(vec(v2.pos).sub(v1.pos), vec(v3.pos).sub(v1.pos)); 56 if(!areaweight) norm.normalize(); 57 v1.norm.add(norm); 58 v2.norm.add(norm); 59 v3.norm.add(norm); 60 } 61 loopi(numverts) fverts[i].norm.normalize(); 62 } 63 } 64 calctangentsvertmodel::vertmesh65 void calctangents() 66 { 67 if(bumpverts) return; 68 vec *tangent = new vec[2*numverts], *bitangent = tangent+numverts; 69 memset(tangent, 0, 2*numverts*sizeof(vec)); 70 bumpverts = new bumpvert[((vertmeshgroup *)group)->numframes*numverts]; 71 loopk(((vertmeshgroup *)group)->numframes) 72 { 73 vert *fverts = &verts[k*numverts]; 74 loopi(numtris) 75 { 76 const tri &t = tris[i]; 77 const tcvert &tc0 = tcverts[t.vert[0]], 78 &tc1 = tcverts[t.vert[1]], 79 &tc2 = tcverts[t.vert[2]]; 80 81 vec v0(fverts[t.vert[0]].pos), 82 e1(fverts[t.vert[1]].pos), 83 e2(fverts[t.vert[2]].pos); 84 e1.sub(v0); 85 e2.sub(v0); 86 87 float u1 = tc1.u - tc0.u, v1 = tc1.v - tc0.v, 88 u2 = tc2.u - tc0.u, v2 = tc2.v - tc0.v, 89 scale = u1*v2 - u2*v1; 90 if(scale!=0) scale = 1.0f / scale; 91 vec u(e1), v(e2); 92 u.mul(v2).sub(vec(e2).mul(v1)).mul(scale); 93 v.mul(u1).sub(vec(e1).mul(u2)).mul(scale); 94 95 loopj(3) 96 { 97 tangent[t.vert[j]].add(u); 98 bitangent[t.vert[j]].add(v); 99 } 100 } 101 bumpvert *fbumpverts = &bumpverts[k*numverts]; 102 loopi(numverts) 103 { 104 const vec &n = fverts[i].norm, 105 &t = tangent[i], 106 &bt = bitangent[i]; 107 bumpvert &bv = fbumpverts[i]; 108 (bv.tangent = t).sub(vec(n).mul(n.dot(t))).normalize(); 109 bv.bitangent = vec().cross(n, t).dot(bt) < 0 ? -1 : 1; 110 } 111 } 112 delete[] tangent; 113 } 114 calcbbvertmodel::vertmesh115 void calcbb(int frame, vec &bbmin, vec &bbmax, const matrix3x4 &m) 116 { 117 vert *fverts = &verts[frame*numverts]; 118 loopj(numverts) 119 { 120 vec v = m.transform(fverts[j].pos); 121 loopi(3) 122 { 123 bbmin[i] = min(bbmin[i], v[i]); 124 bbmax[i] = max(bbmax[i], v[i]); 125 } 126 } 127 } 128 gentrisvertmodel::vertmesh129 void gentris(int frame, Texture *tex, vector<BIH::tri> *out, const matrix3x4 &m) 130 { 131 vert *fverts = &verts[frame*numverts]; 132 loopj(numtris) 133 { 134 BIH::tri &t = out[noclip ? 1 : 0].add(); 135 t.tex = tex->bpp==4 ? tex : NULL; 136 t.a = m.transform(fverts[tris[j].vert[0]].pos); 137 t.b = m.transform(fverts[tris[j].vert[1]].pos); 138 t.c = m.transform(fverts[tris[j].vert[2]].pos); 139 tcvert &av = tcverts[tris[j].vert[0]], 140 &bv = tcverts[tris[j].vert[1]], 141 &cv = tcverts[tris[j].vert[2]]; 142 t.tc[0] = av.u; 143 t.tc[1] = av.v; 144 t.tc[2] = bv.u; 145 t.tc[3] = bv.v; 146 t.tc[4] = cv.u; 147 t.tc[5] = cv.v; 148 } 149 } 150 comparevertvertmodel::vertmesh151 static inline bool comparevert(vvertff &w, int j, tcvert &tc, vert &v) 152 { 153 return tc.u==w.u && tc.v==w.v && v.pos==w.pos; 154 } 155 comparevertvertmodel::vertmesh156 static inline bool comparevert(vvert &w, int j, tcvert &tc, vert &v) 157 { 158 return tc.u==w.u && tc.v==w.v && v.pos==w.pos && v.norm==w.norm; 159 } 160 comparevertvertmodel::vertmesh161 inline bool comparevert(vvertbump &w, int j, tcvert &tc, vert &v) 162 { 163 return tc.u==w.u && tc.v==w.v && v.pos==w.pos && v.norm==w.norm && (!bumpverts || (bumpverts[j].tangent==w.tangent && bumpverts[j].bitangent==w.bitangent)); 164 } 165 assignvertvertmodel::vertmesh166 static inline void assignvert(vvertff &vv, int j, tcvert &tc, vert &v) 167 { 168 vv.pos = v.pos; 169 vv.u = tc.u; 170 vv.v = tc.v; 171 } 172 assignvertvertmodel::vertmesh173 static inline void assignvert(vvert &vv, int j, tcvert &tc, vert &v) 174 { 175 vv.pos = v.pos; 176 vv.norm = v.norm; 177 vv.u = tc.u; 178 vv.v = tc.v; 179 } 180 assignvertvertmodel::vertmesh181 inline void assignvert(vvertbump &vv, int j, tcvert &tc, vert &v) 182 { 183 vv.pos = v.pos; 184 vv.norm = v.norm; 185 vv.u = tc.u; 186 vv.v = tc.v; 187 if(bumpverts) 188 { 189 vv.tangent = bumpverts[j].tangent; 190 vv.bitangent = bumpverts[j].bitangent; 191 } 192 } 193 194 template<class T> genvbovertmodel::vertmesh195 int genvbo(vector<ushort> &idxs, int offset, vector<T> &vverts) 196 { 197 voffset = offset; 198 eoffset = idxs.length(); 199 minvert = 0xFFFF; 200 loopi(numtris) 201 { 202 tri &t = tris[i]; 203 loopj(3) 204 { 205 int index = t.vert[j]; 206 tcvert &tc = tcverts[index]; 207 vert &v = verts[index]; 208 loopvk(vverts) 209 { 210 if(comparevert(vverts[k], index, tc, v)) { minvert = min(minvert, (ushort)k); idxs.add((ushort)k); goto found; } 211 } 212 idxs.add(vverts.length()); 213 assignvert(vverts.add(), index, tc, v); 214 found:; 215 } 216 } 217 minvert = min(minvert, ushort(voffset)); 218 maxvert = max(minvert, ushort(vverts.length()-1)); 219 elen = idxs.length()-eoffset; 220 return vverts.length()-voffset; 221 } 222 genvbovertmodel::vertmesh223 int genvbo(vector<ushort> &idxs, int offset) 224 { 225 voffset = offset; 226 eoffset = idxs.length(); 227 loopi(numtris) 228 { 229 tri &t = tris[i]; 230 loopj(3) idxs.add(voffset+t.vert[j]); 231 } 232 minvert = voffset; 233 maxvert = voffset + numverts-1; 234 elen = idxs.length()-eoffset; 235 return numverts; 236 } 237 filltcvertmodel::vertmesh238 void filltc(uchar *vdata, size_t stride) 239 { 240 vdata = (uchar *)&((vvertff *)&vdata[voffset*stride])->u; 241 loopi(numverts) 242 { 243 *(tcvert *)vdata = tcverts[i]; 244 vdata += stride; 245 } 246 } 247 interpvertsvertmodel::vertmesh248 void interpverts(const animstate &as, bool norms, bool tangents, void *vdata, skin &s) 249 { 250 vert *vert1 = &verts[as.cur.fr1 * numverts], 251 *vert2 = &verts[as.cur.fr2 * numverts], 252 *pvert1 = as.interp<1 ? &verts[as.prev.fr1 * numverts] : NULL, 253 *pvert2 = as.interp<1 ? &verts[as.prev.fr2 * numverts] : NULL; 254 #define ip(p1, p2, t) (p1+t*(p2-p1)) 255 #define ip_v(p, c, t) ip(p##1[i].c, p##2[i].c, t) 256 #define ip_v_ai(c) ip(ip_v(pvert, c, as.prev.t), ip_v(vert, c, as.cur.t), as.interp) 257 #define ip_pos vec(ip_v(vert, pos.x, as.cur.t), ip_v(vert, pos.y, as.cur.t), ip_v(vert, pos.z, as.cur.t)) 258 #define ip_pos_ai vec(ip_v_ai(pos.x), ip_v_ai(pos.y), ip_v_ai(pos.z)) 259 #define ip_norm vec(ip_v(vert, norm.x, as.cur.t), ip_v(vert, norm.y, as.cur.t), ip_v(vert, norm.z, as.cur.t)) 260 #define ip_norm_ai vec(ip_v_ai(norm.x), ip_v_ai(norm.y), ip_v_ai(norm.z)) 261 #define ip_b_ai(c) ip(ip_v(bpvert, c, as.prev.t), ip_v(bvert, c, as.cur.t), as.interp) 262 #define ip_tangent vec(ip_v(bvert, tangent.x, as.cur.t), ip_v(bvert, tangent.y, as.cur.t), ip_v(bvert, tangent.z, as.cur.t)) 263 #define ip_tangent_ai vec(ip_b_ai(tangent.x), ip_b_ai(tangent.y), ip_b_ai(tangent.z)) 264 #define iploop(type, body) \ 265 loopi(numverts) \ 266 { \ 267 type &v = ((type *)vdata)[i]; \ 268 body; \ 269 } 270 if(tangents) 271 { 272 bumpvert *bvert1 = &bumpverts[as.cur.fr1 * numverts], 273 *bvert2 = &bumpverts[as.cur.fr2 * numverts], 274 *bpvert1 = as.interp<1 ? &bumpverts[as.prev.fr1 * numverts] : NULL, 275 *bpvert2 = as.interp<1 ? &bumpverts[as.prev.fr2 * numverts] : NULL; 276 if(as.interp<1) iploop(vvertbump, { v.pos = ip_pos_ai; v.norm = ip_norm_ai; v.tangent = ip_tangent_ai; v.bitangent = bvert1[i].bitangent; }) 277 else iploop(vvertbump, { v.pos = ip_pos; v.norm = ip_norm; v.tangent = ip_tangent; v.bitangent = bvert1[i].bitangent; }) 278 } 279 else if(norms) 280 { 281 if(as.interp<1) iploop(vvert, { v.pos = ip_pos_ai; v.norm = ip_norm_ai; }) 282 else iploop(vvert, { v.pos = ip_pos; v.norm = ip_norm; }) 283 } 284 else if(as.interp<1) iploop(vvertff, v.pos = ip_pos_ai) 285 else iploop(vvertff, v.pos = ip_pos) 286 #undef iploop 287 #undef ip 288 #undef ip_v 289 #undef ip_v_ai 290 #undef ip_pos 291 #undef ip_pos_ai 292 #undef ip_norm 293 #undef ip_norm_ai 294 #undef ip_b_ai 295 #undef ip_tangent 296 #undef ip_tangent_ai 297 } 298 rendervertmodel::vertmesh299 void render(const animstate *as, skin &s, vbocacheentry &vc) 300 { 301 s.bind(this, as); 302 303 if(!(as->anim&ANIM_NOSKIN)) 304 { 305 if(s.multitextured()) 306 { 307 if(!enablemtc || lastmtcbuf!=lastvbuf) 308 { 309 glClientActiveTexture_(GL_TEXTURE1_ARB); 310 if(!enablemtc) glEnableClientState(GL_TEXTURE_COORD_ARRAY); 311 if(lastmtcbuf!=lastvbuf) 312 { 313 vvertff *vverts = hasVBO ? 0 : (vvertff *)vc.vdata; 314 glTexCoordPointer(2, GL_FLOAT, ((vertmeshgroup *)group)->vertsize, &vverts->u); 315 } 316 glClientActiveTexture_(GL_TEXTURE0_ARB); 317 lastmtcbuf = lastvbuf; 318 enablemtc = true; 319 } 320 } 321 else if(enablemtc) disablemtc(); 322 323 if(s.tangents()) 324 { 325 if(!enabletangents || lastxbuf!=lastvbuf) 326 { 327 if(!enabletangents) glEnableVertexAttribArray_(1); 328 if(lastxbuf!=lastvbuf) 329 { 330 vvertbump *vverts = hasVBO ? 0 : (vvertbump *)vc.vdata; 331 glVertexAttribPointer_(1, 4, GL_FLOAT, GL_FALSE, ((vertmeshgroup *)group)->vertsize, &vverts->tangent.x); 332 } 333 lastxbuf = lastvbuf; 334 enabletangents = true; 335 } 336 } 337 else if(enabletangents) disabletangents(); 338 339 if(renderpath==R_FIXEDFUNCTION && (s.scrollu || s.scrollv)) 340 { 341 glMatrixMode(GL_TEXTURE); 342 glPushMatrix(); 343 glTranslatef(s.scrollu*lastmillis/1000.0f, s.scrollv*lastmillis/1000.0f, 0); 344 345 if(s.multitextured()) 346 { 347 glActiveTexture_(GL_TEXTURE1_ARB); 348 glPushMatrix(); 349 glTranslatef(s.scrollu*lastmillis/1000.0f, s.scrollv*lastmillis/1000.0f, 0); 350 } 351 } 352 } 353 354 if(hasDRE) glDrawRangeElements_(GL_TRIANGLES, minvert, maxvert, elen, GL_UNSIGNED_SHORT, &((vertmeshgroup *)group)->edata[eoffset]); 355 else glDrawElements(GL_TRIANGLES, elen, GL_UNSIGNED_SHORT, &((vertmeshgroup *)group)->edata[eoffset]); 356 glde++; 357 xtravertsva += numverts; 358 359 if(renderpath==R_FIXEDFUNCTION && !(as->anim&ANIM_NOSKIN) && (s.scrollu || s.scrollv)) 360 { 361 if(s.multitextured()) 362 { 363 glPopMatrix(); 364 glActiveTexture_(GL_TEXTURE0_ARB); 365 } 366 367 glPopMatrix(); 368 glMatrixMode(GL_MODELVIEW); 369 } 370 371 return; 372 } 373 }; 374 375 struct tag 376 { 377 char *name; 378 matrix3x4 transform; 379 tagvertmodel::tag380 tag() : name(NULL) {} ~tagvertmodel::tag381 ~tag() { DELETEA(name); } 382 }; 383 384 struct vertmeshgroup : meshgroup 385 { 386 int numframes; 387 tag *tags; 388 int numtags; 389 390 static const int MAXVBOCACHE = 16; 391 vbocacheentry vbocache[MAXVBOCACHE]; 392 393 ushort *edata; 394 GLuint ebuf; 395 bool vnorms, vtangents; 396 int vlen, vertsize; 397 uchar *vdata; 398 vertmeshgroupvertmodel::vertmeshgroup399 vertmeshgroup() : numframes(0), tags(NULL), numtags(0), edata(NULL), ebuf(0), vdata(NULL) 400 { 401 } 402 ~vertmeshgroupvertmodel::vertmeshgroup403 virtual ~vertmeshgroup() 404 { 405 DELETEA(tags); 406 if(ebuf) glDeleteBuffers_(1, &ebuf); 407 loopi(MAXVBOCACHE) 408 { 409 DELETEA(vbocache[i].vdata); 410 if(vbocache[i].vbuf) glDeleteBuffers_(1, &vbocache[i].vbuf); 411 } 412 DELETEA(vdata); 413 } 414 findtagvertmodel::vertmeshgroup415 int findtag(const char *name) 416 { 417 loopi(numtags) if(!strcmp(tags[i].name, name)) return i; 418 return -1; 419 } 420 totalframesvertmodel::vertmeshgroup421 int totalframes() const { return numframes; } 422 concattagtransformvertmodel::vertmeshgroup423 void concattagtransform(part *p, int frame, int i, const matrix3x4 &m, matrix3x4 &n) 424 { 425 n.mul(m, tags[frame*numtags + i].transform); 426 n.translate(m.transformnormal(p->translate).mul(p->model->scale)); 427 } 428 calctagmatrixvertmodel::vertmeshgroup429 void calctagmatrix(part *p, int i, const animstate &as, glmatrixf &matrix) 430 { 431 const matrix3x4 &tag1 = tags[as.cur.fr1*numtags + i].transform, 432 &tag2 = tags[as.cur.fr2*numtags + i].transform; 433 #define ip(p1, p2, t) (p1+t*(p2-p1)) 434 #define ip_ai_tag(c) ip( ip( tag1p.c, tag2p.c, as.prev.t), ip( tag1.c, tag2.c, as.cur.t), as.interp) 435 if(as.interp<1) 436 { 437 const matrix3x4 &tag1p = tags[as.prev.fr1*numtags + i].transform, 438 &tag2p = tags[as.prev.fr2*numtags + i].transform; 439 loopj(4) 440 { 441 matrix[4*j+0] = ip_ai_tag(a[j]); 442 matrix[4*j+1] = ip_ai_tag(b[j]); 443 matrix[4*j+2] = ip_ai_tag(c[j]); 444 } 445 } 446 else loopj(4) 447 { 448 matrix[4*j+0] = ip(tag1.a[j], tag2.a[j], as.cur.t); 449 matrix[4*j+1] = ip(tag1.b[j], tag2.b[j], as.cur.t); 450 matrix[4*j+2] = ip(tag1.c[j], tag2.c[j], as.cur.t); 451 } 452 #undef ip_ai_tag 453 #undef ip 454 matrix[12] = (matrix[12] + p->translate.x) * p->model->scale * sizescale; 455 matrix[13] = (matrix[13] + p->translate.y) * p->model->scale * sizescale; 456 matrix[14] = (matrix[14] + p->translate.z) * p->model->scale * sizescale; 457 matrix[3] = matrix[7] = matrix[11] = 0.0f; 458 matrix[15] = 1.0f; 459 } 460 genvbovertmodel::vertmeshgroup461 void genvbo(bool norms, bool tangents, vbocacheentry &vc) 462 { 463 if(hasVBO) 464 { 465 if(!vc.vbuf) glGenBuffers_(1, &vc.vbuf); 466 if(ebuf) return; 467 } 468 else if(edata) 469 { 470 #define ALLOCVDATA(vdata) \ 471 do \ 472 { \ 473 DELETEA(vdata); \ 474 vdata = new uchar[vlen*vertsize]; \ 475 loopv(meshes) ((vertmesh *)meshes[i])->filltc(vdata, vertsize); \ 476 } while(0) 477 if(!vc.vdata) ALLOCVDATA(vc.vdata); 478 return; 479 } 480 481 vector<ushort> idxs; 482 483 vnorms = norms; 484 vtangents = tangents; 485 vertsize = tangents ? sizeof(vvertbump) : (norms ? sizeof(vvert) : sizeof(vvertff)); 486 vlen = 0; 487 if(numframes>1) 488 { 489 loopv(meshes) vlen += ((vertmesh *)meshes[i])->genvbo(idxs, vlen); 490 DELETEA(vdata); 491 if(hasVBO) ALLOCVDATA(vdata); 492 else ALLOCVDATA(vc.vdata); 493 } 494 else 495 { 496 if(hasVBO) glBindBuffer_(GL_ARRAY_BUFFER_ARB, vc.vbuf); 497 #define GENVBO(type) \ 498 do \ 499 { \ 500 vector<type> vverts; \ 501 loopv(meshes) vlen += ((vertmesh *)meshes[i])->genvbo(idxs, vlen, vverts); \ 502 if(hasVBO) glBufferData_(GL_ARRAY_BUFFER_ARB, vverts.length()*sizeof(type), vverts.getbuf(), GL_STATIC_DRAW_ARB); \ 503 else \ 504 { \ 505 DELETEA(vc.vdata); \ 506 vc.vdata = new uchar[vverts.length()*sizeof(type)]; \ 507 memcpy(vc.vdata, vverts.getbuf(), vverts.length()*sizeof(type)); \ 508 } \ 509 } while(0) 510 if(tangents) GENVBO(vvertbump); 511 else if(norms) GENVBO(vvert); 512 else GENVBO(vvertff); 513 } 514 515 if(hasVBO) 516 { 517 glGenBuffers_(1, &ebuf); 518 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, ebuf); 519 glBufferData_(GL_ELEMENT_ARRAY_BUFFER_ARB, idxs.length()*sizeof(ushort), idxs.getbuf(), GL_STATIC_DRAW_ARB); 520 } 521 else 522 { 523 edata = new ushort[idxs.length()]; 524 memcpy(edata, idxs.getbuf(), idxs.length()*sizeof(ushort)); 525 } 526 #undef GENVBO 527 #undef ALLOCVDATA 528 } 529 bindvbovertmodel::vertmeshgroup530 void bindvbo(const animstate *as, vbocacheentry &vc) 531 { 532 vvert *vverts = hasVBO ? 0 : (vvert *)vc.vdata; 533 if(hasVBO && lastebuf!=ebuf) 534 { 535 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, ebuf); 536 lastebuf = ebuf; 537 } 538 if(lastvbuf != (hasVBO ? (void *)(size_t)vc.vbuf : vc.vdata)) 539 { 540 if(hasVBO) glBindBuffer_(GL_ARRAY_BUFFER_ARB, vc.vbuf); 541 if(!lastvbuf) glEnableClientState(GL_VERTEX_ARRAY); 542 glVertexPointer(3, GL_FLOAT, vertsize, &vverts->pos); 543 } 544 lastvbuf = hasVBO ? (void *)(size_t)vc.vbuf : vc.vdata; 545 if(as->anim&ANIM_NOSKIN) 546 { 547 if(enabletc) disabletc(); 548 if(enablenormals) disablenormals(); 549 } 550 else 551 { 552 if(vnorms || vtangents) 553 { 554 if(!enablenormals) 555 { 556 glEnableClientState(GL_NORMAL_ARRAY); 557 enablenormals = true; 558 } 559 if(lastnbuf!=lastvbuf) 560 { 561 glNormalPointer(GL_FLOAT, vertsize, &vverts->norm); 562 lastnbuf = lastvbuf; 563 } 564 } 565 else if(enablenormals) disablenormals(); 566 567 if(!enabletc) 568 { 569 glEnableClientState(GL_TEXTURE_COORD_ARRAY); 570 enabletc = true; 571 } 572 if(lasttcbuf!=lastvbuf) 573 { 574 glTexCoordPointer(2, GL_FLOAT, vertsize, &vverts->u); 575 lasttcbuf = lastnbuf; 576 } 577 } 578 if(enablebones) disablebones(); 579 } 580 cleanupvertmodel::vertmeshgroup581 void cleanup() 582 { 583 loopi(MAXVBOCACHE) 584 { 585 vbocacheentry &c = vbocache[i]; 586 if(c.vbuf) { glDeleteBuffers_(1, &c.vbuf); c.vbuf = 0; } 587 DELETEA(c.vdata); 588 c.as.cur.fr1 = -1; 589 } 590 if(hasVBO) { if(ebuf) { glDeleteBuffers_(1, &ebuf); ebuf = 0; } } 591 else DELETEA(vdata); 592 } 593 rendervertmodel::vertmeshgroup594 void render(const animstate *as, float pitch, const vec &axis, dynent *d, part *p) 595 { 596 if(as->anim&ANIM_NORENDER) 597 { 598 loopv(p->links) calctagmatrix(p, p->links[i].tag, *as, p->links[i].matrix); 599 return; 600 } 601 602 bool norms = false, tangents = false; 603 loopv(p->skins) 604 { 605 if(p->skins[i].normals()) norms = true; 606 if(p->skins[i].tangents()) tangents = true; 607 } 608 if(norms!=vnorms || tangents!=vtangents) { cleanup(); disablevbo(); } 609 vbocacheentry *vc = NULL; 610 if(numframes<=1) vc = vbocache; 611 else 612 { 613 loopi(MAXVBOCACHE) 614 { 615 vbocacheentry &c = vbocache[i]; 616 if(hasVBO ? !c.vbuf : !c.vdata) continue; 617 if(c.as==*as) { vc = &c; break; } 618 } 619 if(!vc) loopi(MAXVBOCACHE) { vc = &vbocache[i]; if((hasVBO ? !vc->vbuf : !vc->vdata) || vc->millis < lastmillis) break; } 620 } 621 if(hasVBO ? !vc->vbuf : !vc->vdata) genvbo(norms, tangents, *vc); 622 if(numframes>1) 623 { 624 if(vc->as!=*as) 625 { 626 vc->as = *as; 627 vc->millis = lastmillis; 628 loopv(meshes) 629 { 630 vertmesh &m = *(vertmesh *)meshes[i]; 631 m.interpverts(*as, norms, tangents, (hasVBO ? vdata : vc->vdata) + m.voffset*vertsize, p->skins[i]); 632 } 633 if(hasVBO) 634 { 635 glBindBuffer_(GL_ARRAY_BUFFER_ARB, vc->vbuf); 636 glBufferData_(GL_ARRAY_BUFFER_ARB, vlen*vertsize, vdata, GL_STREAM_DRAW_ARB); 637 } 638 } 639 vc->millis = lastmillis; 640 } 641 642 bindvbo(as, *vc); 643 loopv(meshes) ((vertmesh *)meshes[i])->render(as, p->skins[i], *vc); 644 645 loopv(p->links) calctagmatrix(p, p->links[i].tag, *as, p->links[i].matrix); 646 } 647 }; 648 vertmodelvertmodel649 vertmodel(const char *name) : animmodel(name) 650 { 651 } 652 }; 653 654