Initial sauer
[SauerbratenRemote.git] / src / engine / vertmodel.h
blob06272523f3dd33864c120552e99b870dade74325
1 VARP(lightmodels, 0, 1, 1);
2 VARP(envmapmodels, 0, 1, 1);
3 VARP(glowmodels, 0, 1, 1);
4 VARP(bumpmodels, 0, 1, 1);
6 struct vertmodel : model
8 struct anpos
10 int fr1, fr2;
11 float t;
13 void setframes(const animstate &as)
15 int time = as.anim&ANIM_SETTIME ? as.basetime : lastmillis-as.basetime;
16 fr1 = (int)(time/as.speed); // round to full frames
17 t = (time-fr1*as.speed)/as.speed; // progress of the frame, value from 0.0f to 1.0f
18 if(as.anim&ANIM_LOOP)
20 fr1 = fr1%as.range+as.frame;
21 fr2 = fr1+1;
22 if(fr2>=as.frame+as.range) fr2 = as.frame;
24 else
26 fr1 = min(fr1, as.range-1)+as.frame;
27 fr2 = min(fr1+1, as.frame+as.range-1);
29 if(as.anim&ANIM_REVERSE)
31 fr1 = (as.frame+as.range-1)-(fr1-as.frame);
32 fr2 = (as.frame+as.range-1)-(fr2-as.frame);
36 bool operator==(const anpos &a) const { return fr1==a.fr1 && fr2==a.fr2 && (fr1==fr2 || t==a.t); }
37 bool operator!=(const anpos &a) const { return fr1!=a.fr1 || fr2!=a.fr2 || (fr1!=fr2 && t!=a.t); }
40 struct vert { vec norm, pos; };
41 struct vvertff { vec pos; float u, v; };
42 struct vvert : vvertff { vec norm; };
43 struct vvertbump : vvert { vec tangent; float bitangent; };
44 struct tcvert { float u, v; };
45 struct bumpvert { vec tangent; float bitangent; };
46 struct tri { ushort vert[3]; };
48 struct part;
50 struct skin
52 part *owner;
53 Texture *tex, *masks, *envmap, *unlittex, *normalmap;
54 int override;
55 Shader *shader;
56 float spec, ambient, glow, fullbright, envmapmin, envmapmax, translucency, scrollu, scrollv, alphatest;
57 bool alphablend;
59 skin() : owner(0), tex(notexture), masks(notexture), envmap(NULL), unlittex(NULL), normalmap(NULL), override(0), shader(NULL), spec(1.0f), ambient(0.3f), glow(3.0f), fullbright(0), envmapmin(0), envmapmax(0), translucency(0.5f), scrollu(0), scrollv(0), alphatest(0.9f), alphablend(true) {}
61 bool multitextured() { return enableglow; }
62 bool envmapped() { return hasCM && envmapmax>0 && envmapmodels && (renderpath!=R_FIXEDFUNCTION || maxtmus >= (refracting && refractfog ? 4 : 3)); }
63 bool bumpmapped() { return renderpath!=R_FIXEDFUNCTION && normalmap && bumpmodels; }
64 bool normals() { return renderpath!=R_FIXEDFUNCTION || (lightmodels && !fullbright) || envmapped() || bumpmapped(); }
65 bool tangents() { return bumpmapped(); }
67 void setuptmus(animstate &as, bool masked)
69 if(fullbright)
71 if(enablelighting) { glDisable(GL_LIGHTING); enablelighting = false; }
73 else if(lightmodels && !enablelighting) { glEnable(GL_LIGHTING); enablelighting = true; }
74 int needsfog = -1;
75 if(refracting && refractfog)
77 needsfog = masked ? 2 : 1;
78 if(fogtmu!=needsfog && fogtmu>=0) disablefog(true);
80 if(masked!=enableglow) lasttex = lastmasks = NULL;
81 if(masked)
83 if(!enableglow) setuptmu(0, "K , C @ T", as.anim&ANIM_ENVMAP && envmapmax>0 ? "Ca * Ta" : NULL);
84 int glowscale = glow>2 ? 4 : (glow > 1 ? 2 : 1);
85 float envmap = as.anim&ANIM_ENVMAP && envmapmax>0 ? 0.2f*envmapmax + 0.8f*envmapmin : 1;
86 colortmu(0, glow/glowscale, glow/glowscale, glow/glowscale);
87 if(fullbright) glColor4f(fullbright/glowscale, fullbright/glowscale, fullbright/glowscale, envmap);
88 else if(lightmodels)
90 GLfloat material[4] = { 1.0f/glowscale, 1.0f/glowscale, 1.0f/glowscale, envmap };
91 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, material);
93 else glColor4f(lightcolor.x/glowscale, lightcolor.y/glowscale, lightcolor.z/glowscale, envmap);
95 glActiveTexture_(GL_TEXTURE1_ARB);
96 if(!enableglow || (!enableenvmap && as.anim&ANIM_ENVMAP && envmapmax>0) || as.anim&ANIM_TRANSLUCENT)
98 if(!enableglow) glEnable(GL_TEXTURE_2D);
99 if(!(as.anim&ANIM_ENVMAP && envmapmax>0) && as.anim&ANIM_TRANSLUCENT) colortmu(1, 0, 0, 0, translucency);
100 setuptmu(1, "P * T", as.anim&ANIM_ENVMAP && envmapmax>0 ? "= Pa" : (as.anim&ANIM_TRANSLUCENT ? "Ta * Ka" : "= Ta"));
102 scaletmu(1, glowscale);
104 if(as.anim&ANIM_ENVMAP && envmapmax>0 && as.anim&ANIM_TRANSLUCENT)
106 glActiveTexture_(GL_TEXTURE0_ARB+envmaptmu);
107 colortmu(envmaptmu, 0, 0, 0, translucency);
110 if(needsfog<0) glActiveTexture_(GL_TEXTURE0_ARB);
112 enableglow = true;
114 else
116 if(enableglow) disableglow();
117 if(fullbright) glColor4f(fullbright, fullbright, fullbright, as.anim&ANIM_TRANSLUCENT ? translucency : 1);
118 else if(lightmodels)
120 GLfloat material[4] = { 1, 1, 1, as.anim&ANIM_TRANSLUCENT ? translucency : 1 };
121 glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, material);
123 else glColor4f(lightcolor.x, lightcolor.y, lightcolor.z, as.anim&ANIM_TRANSLUCENT ? translucency : 1);
125 if(needsfog>=0)
127 if(needsfog!=fogtmu)
129 fogtmu = needsfog;
130 glActiveTexture_(GL_TEXTURE0_ARB+fogtmu);
131 glEnable(GL_TEXTURE_1D);
132 glEnable(GL_TEXTURE_GEN_S);
133 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
134 setuptmu(fogtmu, "K , P @ Ta", masked && as.anim&ANIM_ENVMAP && envmapmax>0 ? "Ka , Pa @ Ta" : "= Pa");
135 uchar wcol[3];
136 getwatercolour(wcol);
137 colortmu(fogtmu, wcol[0]/255.0f, wcol[1]/255.0f, wcol[2]/255.0f, 0);
138 if(!fogtex) createfogtex();
139 glBindTexture(GL_TEXTURE_1D, fogtex);
141 else glActiveTexture_(GL_TEXTURE0_ARB+fogtmu);
142 if(!enablefog) { glEnable(GL_TEXTURE_1D); enablefog = true; }
143 GLfloat s[4] = { -refractfogplane.x/waterfog, -refractfogplane.y/waterfog, -refractfogplane.z/waterfog, -refractfogplane.offset/waterfog };
144 glTexGenfv(GL_S, GL_OBJECT_PLANE, s);
145 glActiveTexture_(GL_TEXTURE0_ARB);
147 if(lightmodels && !fullbright)
149 float ambientk = min(ambient*0.75f, 1),
150 diffusek = 1-ambientk;
151 GLfloat ambientcol[4] = { lightcolor.x*ambientk, lightcolor.y*ambientk, lightcolor.z*ambientk, 1 },
152 diffusecol[4] = { lightcolor.x*diffusek, lightcolor.y*diffusek, lightcolor.z*diffusek, 1 };
153 float ambientmax = max(ambientcol[0], max(ambientcol[1], ambientcol[2])),
154 diffusemax = max(diffusecol[0], max(diffusecol[1], diffusecol[2]));
155 if(ambientmax>1e-3f) loopk(3) ambientcol[k] *= min(1.5f, 1.0f/ambientmax);
156 if(diffusemax>1e-3f) loopk(3) diffusecol[k] *= min(1.5f, 1.0f/diffusemax);
157 glLightfv(GL_LIGHT0, GL_AMBIENT, ambientcol);
158 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffusecol);
162 void setshader(animstate &as, bool masked)
164 if(renderpath==R_FIXEDFUNCTION) setuptmus(as, masked);
165 else
167 if(fullbright)
169 glColor4f(fullbright/2, fullbright/2, fullbright/2, as.anim&ANIM_TRANSLUCENT ? translucency : 1);
170 setenvparamf("ambient", SHPARAM_VERTEX, 3, 2, 2, 2, 1);
171 setenvparamf("ambient", SHPARAM_PIXEL, 3, 2, 2, 2, 1);
173 else
175 glColor4f(lightcolor.x, lightcolor.y, lightcolor.z, as.anim&ANIM_TRANSLUCENT ? translucency : 1);
176 setenvparamf("specscale", SHPARAM_PIXEL, 2, spec, spec, spec);
177 setenvparamf("ambient", SHPARAM_VERTEX, 3, ambient, ambient, ambient, 1);
178 setenvparamf("ambient", SHPARAM_PIXEL, 3, ambient, ambient, ambient, 1);
180 setenvparamf("glowscale", SHPARAM_PIXEL, 4, glow, glow, glow);
181 setenvparamf("millis", SHPARAM_VERTEX, 5, lastmillis/1000.0f, lastmillis/1000.0f, lastmillis/1000.0f);
183 #define SETMODELSHADER(name) \
184 do \
186 static Shader *name##shader = NULL; \
187 if(!name##shader) name##shader = lookupshaderbyname(#name); \
188 name##shader->set(); \
190 while(0)
191 if(shader) shader->set();
192 else if(bumpmapped())
194 if(as.anim&ANIM_ENVMAP && envmapmax>0)
196 if(lightmodels && !fullbright && (masked || spec>=0.01f)) SETMODELSHADER(bumpenvmapmodel);
197 else SETMODELSHADER(bumpenvmapnospecmodel);
198 setlocalparamf("envmapscale", SHPARAM_PIXEL, 6, envmapmin-envmapmax, envmapmax);
200 else if(masked && lightmodels && !fullbright) SETMODELSHADER(bumpmasksmodel);
201 else if(masked && glowmodels) SETMODELSHADER(bumpmasksnospecmodel);
202 else if(spec>=0.01f && lightmodels && !fullbright) SETMODELSHADER(bumpmodel);
203 else SETMODELSHADER(bumpnospecmodel);
205 else if(as.anim&ANIM_ENVMAP && envmapmax>0)
207 if(lightmodels && !fullbright && (masked || spec>=0.01f)) SETMODELSHADER(envmapmodel);
208 else SETMODELSHADER(envmapnospecmodel);
209 setlocalparamf("envmapscale", SHPARAM_VERTEX, 6, envmapmin-envmapmax, envmapmax);
211 else if(masked && lightmodels && !fullbright) SETMODELSHADER(masksmodel);
212 else if(masked && glowmodels) SETMODELSHADER(masksnospecmodel);
213 else if(spec>=0.01f && lightmodels && !fullbright) SETMODELSHADER(stdmodel);
214 else SETMODELSHADER(nospecmodel);
218 void bind(animstate &as)
220 if(as.anim&ANIM_NOSKIN)
222 if(enablealphatest) { glDisable(GL_ALPHA_TEST); enablealphatest = false; }
223 if(!(as.anim&ANIM_SHADOW) && enablealphablend) { glDisable(GL_BLEND); enablealphablend = false; }
224 if(enableglow) disableglow();
225 if(enableenvmap) disableenvmap();
226 if(enablelighting) { glDisable(GL_LIGHTING); enablelighting = false; }
227 if(enablefog) disablefog(true);
228 return;
230 Texture *s = bumpmapped() && unlittex ? unlittex : tex, *m = masks, *n = bumpmapped() ? normalmap : NULL;
231 if(override)
233 Slot &slot = lookuptexture(override);
234 s = slot.sts[0].t;
235 if(slot.sts.length() >= 2)
237 m = slot.sts[1].t;
238 if(n && slot.sts.length() >= 3) n = slot.sts[2].t;
241 if((renderpath==R_FIXEDFUNCTION || !lightmodels) &&
242 (!glowmodels || (renderpath==R_FIXEDFUNCTION && refracting && refractfog && maxtmus<=2)) &&
243 (!envmapmodels || !(as.anim&ANIM_ENVMAP) || envmapmax<=0))
244 m = notexture;
245 setshader(as, m!=notexture);
246 if(s!=lasttex)
248 if(enableglow) glActiveTexture_(GL_TEXTURE1_ARB);
249 glBindTexture(GL_TEXTURE_2D, s->gl);
250 if(enableglow) glActiveTexture_(GL_TEXTURE0_ARB);
251 lasttex = s;
253 if(n && n!=lastnormalmap)
255 glActiveTexture_(GL_TEXTURE3_ARB);
256 glBindTexture(GL_TEXTURE_2D, n->gl);
257 glActiveTexture_(GL_TEXTURE0_ARB);
259 if(s->bpp==32)
261 if(alphablend)
263 if(!enablealphablend && !reflecting && !refracting)
265 glEnable(GL_BLEND);
266 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
267 enablealphablend = true;
270 else if(enablealphablend) { glDisable(GL_BLEND); enablealphablend = false; }
271 if(alphatest>0)
273 if(!enablealphatest) { glEnable(GL_ALPHA_TEST); enablealphatest = true; }
274 if(lastalphatest!=alphatest)
276 glAlphaFunc(GL_GREATER, alphatest);
277 lastalphatest = alphatest;
280 else if(enablealphatest) { glDisable(GL_ALPHA_TEST); enablealphatest = false; }
282 else
284 if(enablealphatest) { glDisable(GL_ALPHA_TEST); enablealphatest = false; }
285 if(enablealphablend && !(as.anim&ANIM_TRANSLUCENT)) { glDisable(GL_BLEND); enablealphablend = false; }
287 if(m!=lastmasks && m!=notexture)
289 if(!enableglow) glActiveTexture_(GL_TEXTURE1_ARB);
290 glBindTexture(GL_TEXTURE_2D, m->gl);
291 if(!enableglow) glActiveTexture_(GL_TEXTURE0_ARB);
292 lastmasks = m;
294 if((renderpath!=R_FIXEDFUNCTION || m!=notexture) && as.anim&ANIM_ENVMAP && envmapmax>0)
296 GLuint emtex = envmap ? envmap->gl : closestenvmaptex;
297 if(!enableenvmap || lastenvmaptex!=emtex)
299 glActiveTexture_(GL_TEXTURE0_ARB+envmaptmu);
300 if(!enableenvmap)
302 glEnable(GL_TEXTURE_CUBE_MAP_ARB);
303 if(!lastenvmaptex && renderpath==R_FIXEDFUNCTION)
305 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
306 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
307 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP_ARB);
308 glEnable(GL_TEXTURE_GEN_S);
309 glEnable(GL_TEXTURE_GEN_T);
310 glEnable(GL_TEXTURE_GEN_R);
312 enableenvmap = true;
314 if(lastenvmaptex!=emtex) { glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, emtex); lastenvmaptex = emtex; }
315 glActiveTexture_(GL_TEXTURE0_ARB);
318 else if(enableenvmap) disableenvmap();
322 struct meshgroup;
324 struct vbocacheentry
326 uchar *vdata;
327 GLuint vbuf;
328 anpos cur, prev;
329 float t;
330 int millis;
332 vbocacheentry() : vdata(NULL), vbuf(0) { cur.fr1 = prev.fr1 = -1; }
335 struct mesh
337 meshgroup *group;
338 char *name;
339 vert *verts;
340 tcvert *tcverts;
341 bumpvert *bumpverts;
342 tri *tris;
343 int numverts, numtris;
345 int voffset, eoffset, elen;
346 ushort minvert, maxvert;
348 mesh() : group(0), name(0), verts(0), tcverts(0), bumpverts(0), tris(0)
352 ~mesh()
354 DELETEA(name);
355 DELETEA(verts);
356 DELETEA(tcverts);
357 DELETEA(bumpverts);
358 DELETEA(tris);
361 mesh *copy()
363 mesh &m = *new mesh;
364 m.name = newstring(name);
365 m.numverts = numverts;
366 m.verts = new vert[numverts*group->numframes];
367 memcpy(m.verts, verts, numverts*group->numframes*sizeof(vert));
368 m.tcverts = new tcvert[numverts];
369 memcpy(m.tcverts, tcverts, numverts*sizeof(tcvert));
370 m.numtris = numtris;
371 m.tris = new tri[numtris];
372 memcpy(m.tris, tris, numtris*sizeof(tri));
373 if(bumpverts)
375 m.bumpverts = new bumpvert[numverts];
376 memcpy(m.bumpverts, bumpverts, numverts*sizeof(bumpvert));
378 else m.bumpverts = NULL;
379 return &m;
382 void calctangents()
384 if(bumpverts) return;
385 vec *tangent = new vec[2*numverts], *bitangent = tangent+numverts;
386 memset(tangent, 0, 2*numverts*sizeof(vec));
387 bumpverts = new bumpvert[group->numframes*numverts];
388 loopk(group->numframes)
390 vert *fverts = &verts[k*numverts];
391 loopi(numtris)
393 const tri &t = tris[i];
394 const tcvert &tc0 = tcverts[t.vert[0]],
395 &tc1 = tcverts[t.vert[1]],
396 &tc2 = tcverts[t.vert[2]];
398 vec v0(fverts[t.vert[0]].pos),
399 e1(fverts[t.vert[1]].pos),
400 e2(fverts[t.vert[2]].pos);
401 e1.sub(v0);
402 e2.sub(v0);
404 float u1 = tc1.u - tc0.u, v1 = tc1.v - tc0.v,
405 u2 = tc2.u - tc0.u, v2 = tc2.v - tc0.v,
406 scale = u1*v2 - u2*v1;
407 if(scale!=0) scale = 1.0f / scale;
408 vec u(e1), v(e2);
409 u.mul(v2).sub(vec(e2).mul(v1)).mul(scale);
410 v.mul(u1).sub(vec(e1).mul(u2)).mul(scale);
412 loopj(3)
414 tangent[t.vert[j]].add(u);
415 bitangent[t.vert[j]].add(v);
418 bumpvert *fbumpverts = &bumpverts[k*numverts];
419 loopi(numverts)
421 const vec &n = fverts[i].norm,
422 &t = tangent[i],
423 &bt = bitangent[i];
424 bumpvert &bv = fbumpverts[i];
425 (bv.tangent = t).sub(vec(n).mul(n.dot(t))).normalize();
426 bv.bitangent = vec().cross(n, t).dot(bt) < 0 ? -1 : 1;
429 delete[] tangent;
432 void calcbb(int frame, vec &bbmin, vec &bbmax, float m[12])
434 vert *fverts = &verts[frame*numverts];
435 loopj(numverts)
437 vec &v = fverts[j].pos;
438 loopi(3)
440 float c = m[i]*v.x + m[i+3]*v.y + m[i+6]*v.z + m[i+9];
441 bbmin[i] = min(bbmin[i], c);
442 bbmax[i] = max(bbmax[i], c);
447 void gentris(int frame, Texture *tex, vector<BIH::tri> &out, float m[12])
449 vert *fverts = &verts[frame*numverts];
450 loopj(numtris)
452 BIH::tri &t = out.add();
453 t.tex = tex->bpp==32 ? tex : NULL;
454 tcvert &av = tcverts[tris[j].vert[0]],
455 &bv = tcverts[tris[j].vert[1]],
456 &cv = tcverts[tris[j].vert[2]];
457 vec &a = fverts[tris[j].vert[0]].pos,
458 &b = fverts[tris[j].vert[1]].pos,
459 &c = fverts[tris[j].vert[2]].pos;
460 loopi(3)
462 t.a[i] = m[i]*a.x + m[i+3]*a.y + m[i+6]*a.z + m[i+9];
463 t.b[i] = m[i]*b.x + m[i+3]*b.y + m[i+6]*b.z + m[i+9];
464 t.c[i] = m[i]*c.x + m[i+3]*c.y + m[i+6]*c.z + m[i+9];
466 t.tc[0] = av.u;
467 t.tc[1] = av.v;
468 t.tc[2] = bv.u;
469 t.tc[3] = bv.v;
470 t.tc[4] = cv.u;
471 t.tc[5] = cv.v;
475 static inline bool comparevert(vvertff &w, int j, tcvert &tc, vert &v)
477 return tc.u==w.u && tc.v==w.v && v.pos==w.pos;
480 static inline bool comparevert(vvert &w, int j, tcvert &tc, vert &v)
482 return tc.u==w.u && tc.v==w.v && v.pos==w.pos && v.norm==w.norm;
485 inline bool comparevert(vvertbump &w, int j, tcvert &tc, vert &v)
487 return tc.u==w.u && tc.v==w.v && v.pos==w.pos && v.norm==w.norm && bumpverts[j].tangent==w.tangent && bumpverts[j].bitangent==w.bitangent;
490 static inline void assignvert(vvertff &vv, int j, tcvert &tc, vert &v)
492 vv.pos = v.pos;
493 vv.u = tc.u;
494 vv.v = tc.v;
497 static inline void assignvert(vvert &vv, int j, tcvert &tc, vert &v)
499 vv.pos = v.pos;
500 vv.norm = v.norm;
501 vv.u = tc.u;
502 vv.v = tc.v;
505 inline void assignvert(vvertbump &vv, int j, tcvert &tc, vert &v)
507 vv.pos = v.pos;
508 vv.norm = v.norm;
509 vv.u = tc.u;
510 vv.v = tc.v;
511 vv.tangent = bumpverts[j].tangent;
512 vv.bitangent = bumpverts[j].bitangent;
515 template<class T>
516 int genvbo(vector<ushort> &idxs, int offset, vector<T> &vverts)
518 voffset = offset;
519 eoffset = idxs.length();
520 minvert = 0xFFFF;
521 loopi(numtris)
523 tri &t = tris[i];
524 loopj(3)
526 tcvert &tc = tcverts[t.vert[j]];
527 vert &v = verts[t.vert[j]];
528 loopvk(vverts)
530 if(comparevert(vverts[k], j, tc, v)) { minvert = min(minvert, (ushort)k); idxs.add((ushort)k); goto found; }
532 idxs.add(vverts.length());
533 assignvert(vverts.add(), j, tc, v);
534 found:;
537 minvert = min(minvert, vverts.length()-1);
538 maxvert = max(minvert, vverts.length()-1);
539 elen = idxs.length()-eoffset;
540 return vverts.length()-voffset;
543 int genvbo(vector<ushort> &idxs, int offset)
545 voffset = offset;
546 eoffset = idxs.length();
547 loopi(numtris)
549 tri &t = tris[i];
550 loopj(3) idxs.add(voffset+t.vert[j]);
552 minvert = voffset;
553 maxvert = voffset + numverts-1;
554 elen = idxs.length()-eoffset;
555 return numverts;
558 void filltc(uchar *vdata, size_t stride)
560 vdata = (uchar *)&((vvertff *)&vdata[voffset*stride])->u;
561 loopi(numverts)
563 *(tcvert *)vdata = tcverts[i];
564 vdata += stride;
568 void interpverts(anpos &cur, anpos *prev, float ai_t, bool norms, bool tangents, void *vdata, skin &s)
570 vert *vert1 = &verts[cur.fr1 * numverts],
571 *vert2 = &verts[cur.fr2 * numverts],
572 *pvert1 = prev ? &verts[prev->fr1 * numverts] : NULL, *pvert2 = prev ? &verts[prev->fr2 * numverts] : NULL;
573 #define ip(p1, p2, t) (p1+t*(p2-p1))
574 #define ip_v(p, c, t) ip(p##1[i].c, p##2[i].c, t)
575 #define ip_v_ai(c) ip(ip_v(pvert, c, prev->t), ip_v(vert, c, cur.t), ai_t)
576 #define ip_pos vec(ip_v(vert, pos.x, cur.t), ip_v(vert, pos.y, cur.t), ip_v(vert, pos.z, cur.t))
577 #define ip_pos_ai vec(ip_v_ai(pos.x), ip_v_ai(pos.y), ip_v_ai(pos.z))
578 #define ip_norm vec(ip_v(vert, norm.x, cur.t), ip_v(vert, norm.y, cur.t), ip_v(vert, norm.z, cur.t))
579 #define ip_norm_ai vec(ip_v_ai(norm.x), ip_v_ai(norm.y), ip_v_ai(norm.z))
580 #define ip_b_ai(c) ip(ip_v(bpvert, c, prev->t), ip_v(bvert, c, cur.t), ai_t)
581 #define ip_tangent vec(ip_v(bvert, tangent.x, cur.t), ip_v(bvert, tangent.y, cur.t), ip_v(bvert, tangent.z, cur.t))
582 #define ip_tangent_ai vec(ip_b_ai(tangent.x), ip_b_ai(tangent.y), ip_b_ai(tangent.z))
583 #define iploop(type, body) \
584 loopi(numverts) \
586 type &v = ((type *)vdata)[i]; \
587 body; \
589 if(tangents)
591 bumpvert *bvert1 = &bumpverts[cur.fr1 * numverts],
592 *bvert2 = &bumpverts[cur.fr2 * numverts],
593 *bpvert1 = prev ? &bumpverts[prev->fr1 * numverts] : NULL, *bpvert2 = prev ? &bumpverts[prev->fr2 * numverts] : NULL;
594 if(prev) iploop(vvertbump, { v.pos = ip_pos_ai; v.norm = ip_norm_ai; v.tangent = ip_tangent_ai; v.bitangent = bvert1[i].bitangent; })
595 else iploop(vvertbump, { v.pos = ip_pos; v.norm = ip_norm; v.tangent = ip_tangent; v.bitangent = bvert1[i].bitangent; })
597 else if(norms)
599 if(prev) iploop(vvert, { v.pos = ip_pos_ai; v.norm = ip_norm_ai; })
600 else iploop(vvert, { v.pos = ip_pos; v.norm = ip_norm; })
602 else if(prev) iploop(vvertff, v.pos = ip_pos_ai)
603 else iploop(vvertff, v.pos = ip_pos)
604 #undef iploop
605 #undef ip
606 #undef ip_v
607 #undef ip_v_ai
610 void render(animstate &as, anpos &cur, anpos *prev, float ai_t, skin &s, vbocacheentry &vc)
612 s.bind(as);
614 if(s.multitextured() || s.tangents())
616 if(!enablemtc || lastmtcbuf!=lastvbuf)
618 glClientActiveTexture_(GL_TEXTURE1_ARB);
619 if(!enablemtc) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
620 if(lastmtcbuf!=lastvbuf)
622 size_t vertsize = group->vtangents ? sizeof(vvertbump) : (group->vnorms ? sizeof(vvert) : sizeof(vvertff));
623 vvertbump *vverts = hasVBO ? 0 : (vvertbump *)vc.vdata;
624 glTexCoordPointer(s.tangents() ? 4 : 2, GL_FLOAT, vertsize, s.tangents() ? &vverts->tangent.x : &vverts->u);
626 glClientActiveTexture_(GL_TEXTURE0_ARB);
627 lastmtcbuf = lastvbuf;
628 enablemtc = true;
631 else if(enablemtc) disablemtc();
633 if(renderpath==R_FIXEDFUNCTION && (s.scrollu || s.scrollv))
635 glMatrixMode(GL_TEXTURE);
636 glPushMatrix();
637 glTranslatef(s.scrollu*lastmillis/1000.0f, s.scrollv*lastmillis/1000.0f, 0);
639 if(s.multitextured())
641 glActiveTexture_(GL_TEXTURE1_ARB);
642 glPushMatrix();
643 glTranslatef(s.scrollu*lastmillis/1000.0f, s.scrollv*lastmillis/1000.0f, 0);
647 extern int mesa_dre_bug;
648 if(hasDRE) glDrawRangeElements_(GL_TRIANGLES, mesa_dre_bug ? max(minvert-3, 0) : minvert, maxvert, elen, GL_UNSIGNED_SHORT, &group->edata[eoffset]);
649 else glDrawElements(GL_TRIANGLES, elen, GL_UNSIGNED_SHORT, &group->edata[eoffset]);
650 glde++;
651 xtravertsva += numverts;
653 if(renderpath==R_FIXEDFUNCTION && (s.scrollu || s.scrollv))
655 if(s.multitextured())
657 glPopMatrix();
658 glActiveTexture_(GL_TEXTURE0_ARB);
661 glPopMatrix();
662 glMatrixMode(GL_MODELVIEW);
665 return;
669 struct tag
671 char *name;
672 vec pos;
673 float transform[3][3];
675 tag() : name(NULL) {}
676 ~tag() { DELETEA(name); }
679 struct meshgroup
681 meshgroup *next;
682 int shared;
683 char *name;
684 vector<mesh *> meshes;
685 tag *tags;
686 int numtags, numframes;
687 float scale;
688 vec translate;
690 static const int MAXVBOCACHE = 8;
691 vbocacheentry vbocache[MAXVBOCACHE];
693 ushort *edata;
694 GLuint ebuf;
695 bool vnorms, vtangents;
696 int vlen;
697 uchar *vdata;
699 meshgroup() : next(NULL), shared(0), name(NULL), tags(NULL), numtags(0), numframes(0), scale(1), translate(0, 0, 0), edata(NULL), ebuf(0), vdata(NULL)
703 virtual ~meshgroup()
705 DELETEA(name);
706 meshes.deletecontentsp();
707 DELETEA(tags);
708 if(ebuf) glDeleteBuffers_(1, &ebuf);
709 loopi(MAXVBOCACHE)
711 DELETEA(vbocache[i].vdata);
712 if(vbocache[i].vbuf) glDeleteBuffers_(1, &vbocache[i].vbuf);
714 DELETEA(vdata);
715 DELETEP(next);
718 int findtag(const char *name)
720 loopi(numtags) if(!strcmp(tags[i].name, name)) return i;
721 return -1;
724 vec anyvert(int frame)
726 loopv(meshes) if(meshes[i]->numverts) return meshes[i]->verts[frame*meshes[i]->numverts].pos;
727 return vec(0, 0, 0);
730 void calcbb(int frame, vec &bbmin, vec &bbmax, float m[12])
732 loopv(meshes) meshes[i]->calcbb(frame, bbmin, bbmax, m);
735 void gentris(int frame, vector<skin> &skins, vector<BIH::tri> &tris, float m[12])
737 loopv(meshes) meshes[i]->gentris(frame, skins[i].tex, tris, m);
740 bool hasframe(int i) { return i>=0 && i<numframes; }
741 bool hasframes(int i, int n) { return i>=0 && i+n<=numframes; }
742 int clipframes(int i, int n) { return min(n, numframes - i); }
744 meshgroup *copy()
746 meshgroup &group = *new meshgroup;
747 group.name = newstring(name);
748 loopv(meshes) group.meshes.add(meshes[i]->copy())->group = &group;
749 group.numtags = numtags;
750 group.tags = new tag[numframes*numtags];
751 memcpy(group.tags, tags, numframes*numtags*sizeof(tag));
752 loopi(numframes*numtags) if(group.tags[i].name) group.tags[i].name = newstring(group.tags[i].name);
753 group.numframes = numframes;
754 group.scale = scale;
755 group.translate = translate;
756 return &group;
759 meshgroup *scaleverts(const float nscale, const vec &ntranslate)
761 if(nscale==scale && ntranslate==translate) { shared++; return this; }
762 else if(next || shared)
764 if(!next) next = copy();
765 return next->scaleverts(nscale, ntranslate);
767 float scalediff = nscale/scale;
768 vec transdiff(ntranslate);
769 transdiff.sub(translate);
770 transdiff.mul(scale);
771 loopv(meshes)
773 mesh &m = *meshes[i];
774 loopj(numframes*m.numverts) m.verts[j].pos.add(transdiff).mul(scalediff);
776 loopi(numframes*numtags) tags[i].pos.add(transdiff).mul(scalediff);
777 scale = nscale;
778 translate = ntranslate;
779 shared++;
780 return this;
783 void concattagtransform(int frame, int i, float m[12], float n[12])
785 tag &t = tags[frame*numtags + i];
786 loop(y, 3)
788 n[y] = m[y]*t.transform[0][0] + m[y+3]*t.transform[0][1] + m[y+6]*t.transform[0][2];
789 n[3+y] = m[y]*t.transform[1][0] + m[y+3]*t.transform[1][1] + m[y+6]*t.transform[1][2];
790 n[6+y] = m[y]*t.transform[2][0] + m[y+3]*t.transform[2][1] + m[y+6]*t.transform[2][2];
791 n[9+y] = m[y]*t.pos[0] + m[y+3]*t.pos[1] + m[y+6]*t.pos[2] + m[y+9];
795 void calctagmatrix(int i, const anpos &cur, const anpos *prev, float ai_t, GLfloat *matrix)
797 tag *tag1 = &tags[cur.fr1*numtags + i];
798 tag *tag2 = &tags[cur.fr2*numtags + i];
799 #define ip(p1, p2, t) (p1+t*(p2-p1))
800 #define ip_ai_tag(c) ip( ip( tag1p->c, tag2p->c, prev->t), ip( tag1->c, tag2->c, cur.t), ai_t)
801 if(prev)
803 tag *tag1p = &tags[prev->fr1*numtags + i];
804 tag *tag2p = &tags[prev->fr2*numtags + i];
805 loopj(3) matrix[j] = ip_ai_tag(transform[0][j]); // transform
806 loopj(3) matrix[4 + j] = ip_ai_tag(transform[1][j]);
807 loopj(3) matrix[8 + j] = ip_ai_tag(transform[2][j]);
808 loopj(3) matrix[12 + j] = ip_ai_tag(pos[j]); // position
810 else
812 loopj(3) matrix[j] = ip(tag1->transform[0][j], tag2->transform[0][j], cur.t); // transform
813 loopj(3) matrix[4 + j] = ip(tag1->transform[1][j], tag2->transform[1][j], cur.t);
814 loopj(3) matrix[8 + j] = ip(tag1->transform[2][j], tag2->transform[2][j], cur.t);
815 loopj(3) matrix[12 + j] = ip(tag1->pos[j], tag2->pos[j], cur.t); // position
817 #undef ip_ai_tag
818 #undef ip
819 matrix[3] = matrix[7] = matrix[11] = 0.0f;
820 matrix[15] = 1.0f;
823 void genvbo(bool norms, bool tangents, vbocacheentry &vc)
825 if(hasVBO)
827 if(!vc.vbuf) glGenBuffers_(1, &vc.vbuf);
828 if(ebuf) return;
830 else if(edata)
832 #define ALLOCVDATA(vdata) \
833 do \
835 DELETEA(vdata); \
836 size_t vertsize = tangents ? sizeof(vvertbump) : (norms ? sizeof(vvert) : sizeof(vvertff)); \
837 vdata = new uchar[vlen*vertsize]; \
838 loopv(meshes) meshes[i]->filltc(vdata, vertsize); \
839 } while(0)
840 if(!vc.vdata) ALLOCVDATA(vc.vdata);
841 return;
844 vector<ushort> idxs;
846 vnorms = norms;
847 vtangents = tangents;
848 vlen = 0;
849 if(numframes>1)
851 loopv(meshes) vlen += meshes[i]->genvbo(idxs, vlen);
852 DELETEA(vdata);
853 if(hasVBO) ALLOCVDATA(vdata);
854 else ALLOCVDATA(vc.vdata);
856 else
858 if(hasVBO) glBindBuffer_(GL_ARRAY_BUFFER_ARB, vc.vbuf);
859 #define GENVBO(type) \
860 do \
862 vector<type> vverts; \
863 loopv(meshes) vlen += meshes[i]->genvbo(idxs, vlen, vverts); \
864 if(hasVBO) glBufferData_(GL_ARRAY_BUFFER_ARB, vverts.length()*sizeof(type), vverts.getbuf(), GL_STATIC_DRAW_ARB); \
865 else \
867 DELETEA(vc.vdata); \
868 vc.vdata = new uchar[vverts.length()*sizeof(type)]; \
869 memcpy(vc.vdata, vverts.getbuf(), vverts.length()*sizeof(type)); \
871 } while(0)
872 if(tangents) GENVBO(vvertbump);
873 else if(norms) GENVBO(vvert);
874 else GENVBO(vvertff);
877 if(hasVBO)
879 glGenBuffers_(1, &ebuf);
880 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, ebuf);
881 glBufferData_(GL_ELEMENT_ARRAY_BUFFER_ARB, idxs.length()*sizeof(ushort), idxs.getbuf(), GL_STATIC_DRAW_ARB);
883 else
885 edata = new ushort[idxs.length()];
886 memcpy(edata, idxs.getbuf(), idxs.length()*sizeof(ushort));
890 void bindvbo(animstate &as, vbocacheentry &vc)
892 size_t vertsize = vtangents ? sizeof(vvertbump) : (vnorms ? sizeof(vvert) : sizeof(vvertff));
893 vvert *vverts = hasVBO ? 0 : (vvert *)vc.vdata;
894 if(hasVBO && lastebuf!=ebuf)
896 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, ebuf);
897 lastebuf = ebuf;
899 if(lastvbuf != (hasVBO ? (void *)(size_t)vc.vbuf : vc.vdata))
901 if(hasVBO) glBindBuffer_(GL_ARRAY_BUFFER_ARB, vc.vbuf);
902 if(!lastvbuf) glEnableClientState(GL_VERTEX_ARRAY);
903 glVertexPointer(3, GL_FLOAT, vertsize, &vverts->pos);
905 lastvbuf = hasVBO ? (void *)(size_t)vc.vbuf : vc.vdata;
906 if(as.anim&ANIM_NOSKIN)
908 if(enabletc) disabletc();
910 else if(!enabletc || lasttcbuf!=lastvbuf)
912 if(vnorms || vtangents)
914 if(!enabletc) glEnableClientState(GL_NORMAL_ARRAY);
915 if(lasttcbuf!=lastvbuf) glNormalPointer(GL_FLOAT, vertsize, &vverts->norm);
917 if(!enabletc) glEnableClientState(GL_TEXTURE_COORD_ARRAY);
918 if(lasttcbuf!=lastvbuf) glTexCoordPointer(2, GL_FLOAT, vertsize, &vverts->u);
919 lasttcbuf = lastvbuf;
920 enabletc = true;
924 void render(animstate &as, anpos &cur, anpos *prev, float ai_t, vector<skin> &skins)
926 bool norms = false, tangents = false;
927 loopv(skins)
929 if(skins[i].normals()) norms = true;
930 if(skins[i].tangents()) tangents = true;
932 if(norms!=vnorms || tangents!=vtangents)
934 loopi(MAXVBOCACHE)
936 vbocacheentry &c = vbocache[i];
937 if(c.vbuf) { glDeleteBuffers_(1, &c.vbuf); c.vbuf = 0; }
938 DELETEA(c.vdata);
939 c.cur.fr1 = -1;
941 if(hasVBO) { if(ebuf) { glDeleteBuffers_(1, &ebuf); ebuf = 0; } }
942 else DELETEA(vdata);
943 lastvbuf = lasttcbuf = lastmtcbuf = NULL;
944 lastebuf = 0;
946 vbocacheentry *vc = NULL;
947 if(numframes<=1) vc = vbocache;
948 else
950 loopi(MAXVBOCACHE)
952 vbocacheentry &c = vbocache[i];
953 if(hasVBO ? !c.vbuf : !c.vdata) continue;
954 if(c.cur==cur && (prev ? c.prev==*prev && c.t==ai_t : c.prev.fr1<0)) { vc = &c; break; }
956 if(!vc) loopi(MAXVBOCACHE) { vc = &vbocache[i]; if((hasVBO ? !vc->vbuf : !vc->vdata) || vc->millis < lastmillis) break; }
958 if(hasVBO ? !vc->vbuf : !vc->vdata) genvbo(norms, tangents, *vc);
959 if(numframes>1)
961 if(vc->cur!=cur || (prev ? vc->prev!=*prev || vc->t!=ai_t : vc->prev.fr1>=0))
963 vc->cur = cur;
964 if(prev) { vc->prev = *prev; vc->t = ai_t; }
965 else vc->prev.fr1 = -1;
966 vc->millis = lastmillis;
967 size_t vertsize = tangents ? sizeof(vvertbump) : (norms ? sizeof(vvert) : sizeof(vvertff));
968 loopv(meshes)
970 mesh &m = *meshes[i];
971 m.interpverts(cur, prev, ai_t, norms, tangents, (hasVBO ? vdata : vc->vdata) + m.voffset*vertsize, skins[i]);
973 if(hasVBO)
975 glBindBuffer_(GL_ARRAY_BUFFER_ARB, vc->vbuf);
976 glBufferData_(GL_ARRAY_BUFFER_ARB, vlen*vertsize, vdata, GL_STREAM_DRAW_ARB);
981 bindvbo(as, *vc);
982 loopv(meshes) meshes[i]->render(as, cur, prev, ai_t, skins[i], *vc);
986 struct animinfo
988 int frame, range;
989 float speed;
990 int priority;
993 struct linkedpart
995 part *p;
996 int anim, basetime;
998 linkedpart() : p(NULL), anim(-1), basetime(0) {}
1001 struct part
1003 vertmodel *model;
1004 int index;
1005 meshgroup *meshes;
1006 vector<linkedpart> links;
1007 vector<skin> skins;
1008 vector<animinfo> *anims;
1009 float pitchscale, pitchoffset, pitchmin, pitchmax;
1011 part() : meshes(NULL), anims(NULL), pitchscale(1), pitchoffset(0), pitchmin(0), pitchmax(0) {}
1012 virtual ~part()
1014 DELETEA(anims);
1017 void calcbb(int frame, vec &bbmin, vec &bbmax)
1019 float m[12] = { 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 };
1020 calcbb(frame, bbmin, bbmax, m);
1023 void calcbb(int frame, vec &bbmin, vec &bbmax, float m[12])
1025 meshes->calcbb(frame, bbmin, bbmax, m);
1026 loopv(links) if(links[i].p)
1028 float n[12];
1029 meshes->concattagtransform(frame, i, m, n);
1030 links[i].p->calcbb(frame, bbmin, bbmax, n);
1034 void gentris(int frame, vector<BIH::tri> &tris)
1036 float m[12] = { 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 };
1037 gentris(frame, tris, m);
1040 void gentris(int frame, vector<BIH::tri> &tris, float m[12])
1042 meshes->gentris(frame, skins, tris, m);
1043 loopv(links) if(links[i].p)
1045 float n[12];
1046 meshes->concattagtransform(frame, i, m, n);
1047 links[i].p->gentris(frame, tris, n);
1051 bool link(part *link, const char *tag, int anim = -1, int basetime = 0)
1053 int i = meshes->findtag(tag);
1054 if(i<0) return false;
1055 while(i>=links.length()) links.add();
1056 links[i].p = link;
1057 links[i].anim = anim;
1058 links[i].basetime = basetime;
1059 return true;
1062 void initskins(Texture *tex = notexture, Texture *masks = notexture)
1064 if(!meshes) return;
1065 while(skins.length() < meshes->meshes.length())
1067 skin &s = skins.add();
1068 s.owner = this;
1069 s.tex = tex;
1070 s.masks = masks;
1074 virtual void getdefaultanim(animstate &as, int anim, int varseed, dynent *d)
1076 as.frame = 0;
1077 as.range = 1;
1080 void getanimspeed(animstate &as, dynent *d)
1082 switch(as.anim&ANIM_INDEX)
1084 case ANIM_FORWARD:
1085 case ANIM_BACKWARD:
1086 case ANIM_LEFT:
1087 case ANIM_RIGHT:
1088 case ANIM_SWIM:
1089 as.speed = 5500.0f/d->maxspeed;
1090 break;
1092 default:
1093 as.speed = 100.0f;
1094 break;
1098 bool calcanimstate(int anim, int varseed, float speed, int basetime, dynent *d, animstate &as)
1100 as.anim = anim;
1101 as.speed = speed;
1102 if(anims)
1104 vector<animinfo> *primary = &anims[anim&ANIM_INDEX];
1105 if((anim>>ANIM_SECONDARY)&ANIM_INDEX)
1107 vector<animinfo> *secondary = &anims[(anim>>ANIM_SECONDARY)&ANIM_INDEX];
1108 if(secondary->length() && (primary->empty() || (*secondary)[0].priority > (*primary)[0].priority))
1110 primary = secondary;
1111 as.anim = anim>>ANIM_SECONDARY;
1114 if(primary->length())
1116 animinfo &ai = (*primary)[uint(varseed)%primary->length()];
1117 as.frame = ai.frame;
1118 as.range = ai.range;
1119 if(ai.speed>0) as.speed = 1000.0f/ai.speed;
1121 else getdefaultanim(as, anim, varseed, d);
1123 else getdefaultanim(as, anim, varseed, d);
1124 if(as.speed<=0) getanimspeed(as, d);
1126 as.anim &= (1<<ANIM_SECONDARY)-1;
1127 as.anim |= anim&ANIM_FLAGS;
1128 as.basetime = basetime;
1129 if(as.anim&(ANIM_LOOP|ANIM_START|ANIM_END) && (anim>>ANIM_SECONDARY)&ANIM_INDEX)
1131 as.anim &= ~ANIM_SETTIME;
1132 as.basetime = -((int)(size_t)d&0xFFF);
1134 if(as.anim&(ANIM_START|ANIM_END))
1136 if(as.anim&ANIM_END) as.frame += as.range-1;
1137 as.range = 1;
1140 if(!meshes->hasframes(as.frame, as.range))
1142 if(!meshes->hasframe(as.frame)) return false;
1143 as.range = meshes->clipframes(as.frame, as.range);
1146 if(d && index<2)
1148 if(d->lastmodel[index]!=this || d->lastanimswitchtime[index]==-1 || lastmillis-d->lastrendered>animationinterpolationtime)
1150 d->prev[index] = d->current[index] = as;
1151 d->lastanimswitchtime[index] = lastmillis-animationinterpolationtime*2;
1153 else if(d->current[index]!=as)
1155 if(lastmillis-d->lastanimswitchtime[index]>animationinterpolationtime/2) d->prev[index] = d->current[index];
1156 d->current[index] = as;
1157 d->lastanimswitchtime[index] = lastmillis;
1159 else if(as.anim&ANIM_SETTIME) d->current[index].basetime = as.basetime;
1160 d->lastmodel[index] = this;
1162 return true;
1165 void calcnormal(GLfloat *m, vec &dir)
1167 vec n(dir);
1168 dir.x = n.x*m[0] + n.y*m[1] + n.z*m[2];
1169 dir.y = n.x*m[4] + n.y*m[5] + n.z*m[6];
1170 dir.z = n.x*m[8] + n.y*m[9] + n.z*m[10];
1173 void calcplane(GLfloat *m, plane &p)
1175 p.offset += p.x*m[12] + p.y*m[13] + p.z*m[14];
1176 calcnormal(m, p);
1179 void calcvertex(GLfloat *m, vec &pos)
1181 vec p(pos);
1183 p.x -= m[12];
1184 p.y -= m[13];
1185 p.z -= m[14];
1187 #if 0
1188 // This is probably overkill, since just about any transformations this encounters will be orthogonal matrices
1189 // where their inverse is simply the transpose.
1190 int a = fabs(m[0])>fabs(m[1]) && fabs(m[0])>fabs(m[2]) ? 0 : (fabs(m[1])>fabs(m[2]) ? 1 : 2), b = (a+1)%3, c = (a+2)%3;
1191 float a1 = m[a], a2 = m[a+4], a3 = m[a+8],
1192 b1 = m[b], b2 = m[b+4], b3 = m[b+8],
1193 c1 = m[c], c2 = m[c+4], c3 = m[c+8];
1195 pos.z = (p[c] - c1*p[a]/a1 - (c2 - c1*a2/a1)*(p[b] - b1*p[a]/a1)/(b2 - b1*a2/a1)) / (c3 - c1*a3/a1 - (c2 - c1*a2/a1)*(b3 - b1*a3/a1)/(b2 - b1*a2/a1));
1196 pos.y = (p[b] - b1*p[a]/a1 - (b3 - b1*a3/a1)*pos.z)/(b2 - b1*a2/a1);
1197 pos.x = (p[a] - a2*pos.y - a3*pos.z)/a1;
1198 #else
1199 pos.x = p.x*m[0] + p.y*m[1] + p.z*m[2];
1200 pos.y = p.x*m[4] + p.y*m[5] + p.z*m[6];
1201 pos.z = p.x*m[8] + p.y*m[9] + p.z*m[10];
1202 #endif
1205 float calcpitchaxis(int anim, GLfloat pitch, vec &axis, vec &dir, vec &campos, plane &fogplane)
1207 float angle = pitchscale*pitch + pitchoffset;
1208 if(pitchmin || pitchmax) angle = max(pitchmin, min(pitchmax, angle));
1209 if(!angle) return 0;
1211 float c = cosf(-angle*RAD), s = sinf(-angle*RAD);
1212 vec d(axis);
1213 axis.rotate(c, s, d);
1214 if(!(anim&ANIM_NOSKIN))
1216 dir.rotate(c, s, d);
1217 campos.rotate(c, s, d);
1218 fogplane.rotate(c, s, d);
1221 return angle;
1224 void render(int anim, int varseed, float speed, int basetime, float pitch, const vec &axis, dynent *d, const vec &dir, const vec &campos, const plane &fogplane)
1226 animstate as;
1227 if(!calcanimstate(anim, varseed, speed, basetime, d, as)) return;
1229 anpos prev, cur;
1230 cur.setframes(d && index<2 ? d->current[index] : as);
1232 float ai_t = 0;
1233 bool doai = d && index<2 && lastmillis-d->lastanimswitchtime[index]<animationinterpolationtime && d->prev[index].range>0;
1234 if(doai)
1236 prev.setframes(d->prev[index]);
1237 ai_t = (lastmillis-d->lastanimswitchtime[index])/(float)animationinterpolationtime;
1240 if(!model->cullface && enablecullface) { glDisable(GL_CULL_FACE); enablecullface = false; }
1241 else if(model->cullface && !enablecullface) { glEnable(GL_CULL_FACE); enablecullface = true; }
1243 vec raxis(axis), rdir(dir), rcampos(campos);
1244 plane rfogplane(fogplane);
1245 float pitchamount = calcpitchaxis(anim, pitch, raxis, rdir, rcampos, rfogplane);
1246 if(pitchamount)
1248 glPushMatrix();
1249 glRotatef(pitchamount, axis.x, axis.y, axis.z);
1250 if(renderpath!=R_FIXEDFUNCTION && anim&ANIM_ENVMAP)
1252 glMatrixMode(GL_TEXTURE);
1253 glPushMatrix();
1254 glRotatef(pitchamount, axis.x, axis.y, axis.z);
1255 glMatrixMode(GL_MODELVIEW);
1259 if(!(anim&ANIM_NOSKIN))
1261 if(renderpath!=R_FIXEDFUNCTION)
1263 if(refracting) setfogplane(rfogplane);
1264 setenvparamf("direction", SHPARAM_VERTEX, 0, rdir.x, rdir.y, rdir.z);
1265 setenvparamf("camera", SHPARAM_VERTEX, 1, rcampos.x, rcampos.y, rcampos.z, 1);
1267 else
1269 if(refracting && refractfog) refractfogplane = rfogplane;
1270 if(lightmodels) loopv(skins) if(!skins[i].fullbright)
1272 GLfloat pos[4] = { rdir.x*1000, rdir.y*1000, rdir.z*1000, 0 };
1273 glLightfv(GL_LIGHT0, GL_POSITION, pos);
1274 break;
1279 meshes->render(as, cur, doai ? &prev : NULL, ai_t, skins);
1281 loopv(links) if(links[i].p) // render the linked models - interpolate rotation and position of the 'link-tags'
1283 part *link = links[i].p;
1285 GLfloat matrix[16];
1286 meshes->calctagmatrix(i, cur, doai ? &prev : NULL, ai_t, matrix);
1288 vec naxis(raxis), ndir(rdir), ncampos(rcampos);
1289 plane nfogplane(rfogplane);
1290 calcnormal(matrix, naxis);
1291 if(!(anim&ANIM_NOSKIN))
1293 calcnormal(matrix, ndir);
1294 calcvertex(matrix, ncampos);
1295 calcplane(matrix, nfogplane);
1298 glPushMatrix();
1299 glMultMatrixf(matrix);
1300 if(renderpath!=R_FIXEDFUNCTION && anim&ANIM_ENVMAP)
1302 glMatrixMode(GL_TEXTURE);
1303 glPushMatrix();
1304 glMultMatrixf(matrix);
1305 glMatrixMode(GL_MODELVIEW);
1307 int nanim = anim, nbasetime = basetime;
1308 if(links[i].anim>=0)
1310 nanim = links[i].anim | (anim&ANIM_FLAGS);
1311 nbasetime = links[i].basetime;
1313 link->render(nanim, varseed, speed, nbasetime, pitch, naxis, d, ndir, ncampos, nfogplane);
1314 if(renderpath!=R_FIXEDFUNCTION && anim&ANIM_ENVMAP)
1316 glMatrixMode(GL_TEXTURE);
1317 glPopMatrix();
1318 glMatrixMode(GL_MODELVIEW);
1320 glPopMatrix();
1323 if(pitchamount)
1325 glPopMatrix();
1326 if(renderpath!=R_FIXEDFUNCTION && anim&ANIM_ENVMAP)
1328 glMatrixMode(GL_TEXTURE);
1329 glPopMatrix();
1330 glMatrixMode(GL_MODELVIEW);
1335 void setanim(int num, int frame, int range, float speed, int priority = 0)
1337 if(frame<0 || range<=0 || !meshes->hasframes(frame, range))
1339 conoutf("invalid frame %d, range %d in model %s", frame, range, model->loadname);
1340 return;
1342 if(!anims) anims = new vector<animinfo>[NUMANIMS];
1343 animinfo &ai = anims[num].add();
1344 ai.frame = frame;
1345 ai.range = range;
1346 ai.speed = speed;
1347 ai.priority = priority;
1351 bool loaded;
1352 char *loadname;
1353 vector<part *> parts;
1355 vertmodel(const char *name) : loaded(false)
1357 loadname = newstring(name);
1360 ~vertmodel()
1362 delete[] loadname;
1363 parts.deletecontentsp();
1366 char *name() { return loadname; }
1368 virtual meshgroup *loadmeshes(char *name) { return NULL; }
1370 meshgroup *sharemeshes(char *name)
1372 static hashtable<char *, vertmodel::meshgroup *> meshgroups;
1373 if(!meshgroups.access(name))
1375 meshgroup *group = loadmeshes(name);
1376 if(!group) return NULL;
1377 meshgroups[group->name] = group;
1379 return meshgroups[name];
1382 void gentris(int frame, vector<BIH::tri> &tris)
1384 if(parts.empty()) return;
1385 parts[0]->gentris(frame, tris);
1388 BIH *setBIH()
1390 if(bih) return bih;
1391 vector<BIH::tri> tris;
1392 gentris(0, tris);
1393 bih = new BIH(tris.length(), tris.getbuf());
1394 return bih;
1397 void calcbb(int frame, vec &center, vec &radius)
1399 if(parts.empty()) return;
1400 vec bbmin, bbmax;
1401 bbmin = bbmax = parts[0]->meshes->anyvert(frame);
1402 parts[0]->calcbb(frame, bbmin, bbmax);
1403 radius = bbmax;
1404 radius.sub(bbmin);
1405 radius.mul(0.5f);
1406 center = bbmin;
1407 center.add(radius);
1410 bool link(part *link, const char *tag, int anim = -1, int basetime = 0)
1412 loopv(parts) if(parts[i]->link(link, tag, anim, basetime)) return true;
1413 return false;
1416 void setskin(int tex = 0)
1418 loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].override = tex;
1421 bool envmapped()
1423 loopv(parts) loopvj(parts[i]->skins) if(parts[i]->skins[j].envmapped()) return true;
1424 return false;
1427 virtual bool loaddefaultparts()
1429 return true;
1432 void setshader(Shader *shader)
1434 if(parts.empty()) loaddefaultparts();
1435 loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].shader = shader;
1438 void setenvmap(float envmapmin, float envmapmax, Texture *envmap)
1440 if(parts.empty()) loaddefaultparts();
1441 loopv(parts) loopvj(parts[i]->skins)
1443 skin &s = parts[i]->skins[j];
1444 if(envmapmax)
1446 s.envmapmin = envmapmin;
1447 s.envmapmax = envmapmax;
1449 if(envmap) s.envmap = envmap;
1453 void setspec(float spec)
1455 if(parts.empty()) loaddefaultparts();
1456 loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].spec = spec;
1459 void setambient(float ambient)
1461 if(parts.empty()) loaddefaultparts();
1462 loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].ambient = ambient;
1465 void setglow(float glow)
1467 if(parts.empty()) loaddefaultparts();
1468 loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].glow = glow;
1471 void setalphatest(float alphatest)
1473 if(parts.empty()) loaddefaultparts();
1474 loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].alphatest = alphatest;
1477 void setalphablend(bool alphablend)
1479 if(parts.empty()) loaddefaultparts();
1480 loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].alphablend = alphablend;
1483 void settranslucency(float translucency)
1485 if(parts.empty()) loaddefaultparts();
1486 loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].translucency = translucency;
1489 void setfullbright(float fullbright)
1491 if(parts.empty()) loaddefaultparts();
1492 loopv(parts) loopvj(parts[i]->skins) parts[i]->skins[j].fullbright = fullbright;
1495 virtual void render(int anim, int varseed, float speed, int basetime, float pitch, const vec &axis, dynent *d, modelattach *a, const vec &dir, const vec &campos, const plane &fogplane)
1499 void render(int anim, int varseed, float speed, int basetime, const vec &o, float yaw, float pitch, dynent *d, modelattach *a, const vec &color, const vec &dir)
1501 vec rdir, campos;
1502 plane fogplane;
1504 yaw += spin*lastmillis/1000.0f;
1506 if(!(anim&ANIM_NOSKIN))
1508 fogplane = plane(0, 0, 1, o.z-refracting);
1510 lightcolor = color;
1512 rdir = dir;
1513 rdir.rotate_around_z((-yaw-180.0f)*RAD);
1515 campos = camera1->o;
1516 campos.sub(o);
1517 campos.rotate_around_z((-yaw-180.0f)*RAD);
1519 if(envmapped()) anim |= ANIM_ENVMAP;
1520 else if(a) for(int i = 0; a[i].name; i++) if(a[i].m && a[i].m->envmapped())
1522 anim |= ANIM_ENVMAP;
1523 break;
1525 if(anim&ANIM_ENVMAP) closestenvmaptex = lookupenvmap(closestenvmap(o));
1528 if(anim&ANIM_ENVMAP)
1530 envmaptmu = 2;
1531 if(renderpath==R_FIXEDFUNCTION)
1533 if(refracting && refractfog) envmaptmu = 3;
1534 glActiveTexture_(GL_TEXTURE0_ARB+envmaptmu);
1536 glMatrixMode(GL_TEXTURE);
1537 if(renderpath==R_FIXEDFUNCTION)
1539 setuptmu(envmaptmu, "T , P @ Pa", anim&ANIM_TRANSLUCENT ? "= Ka" : NULL);
1541 GLfloat mm[16], mmtrans[16];
1542 glGetFloatv(GL_MODELVIEW_MATRIX, mm);
1543 loopi(4) // transpose modelview (mmtrans[4*i+j] = mm[4*j+i]) and convert to (-y, z, x, w)
1545 GLfloat x = mm[i], y = mm[4+i], z = mm[8+i], w = mm[12+i];
1546 mmtrans[4*i] = -y;
1547 mmtrans[4*i+1] = z;
1548 mmtrans[4*i+2] = x;
1549 mmtrans[4*i+3] = w;
1551 glLoadMatrixf(mmtrans);
1553 else
1555 glLoadIdentity();
1556 glTranslatef(o.x, o.y, o.z);
1557 glRotatef(yaw+180, 0, 0, 1);
1559 glMatrixMode(GL_MODELVIEW);
1560 if(renderpath==R_FIXEDFUNCTION) glActiveTexture_(GL_TEXTURE0_ARB);
1563 glPushMatrix();
1564 glTranslatef(o.x, o.y, o.z);
1565 glRotatef(yaw+180, 0, 0, 1);
1567 if(anim&ANIM_TRANSLUCENT)
1569 glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
1570 nocolorshader->set();
1571 render(anim|ANIM_NOSKIN, varseed, speed, basetime, pitch, vec(0, -1, 0), d, a, rdir, campos, fogplane);
1572 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, refracting && renderpath!=R_FIXEDFUNCTION ? GL_FALSE : GL_TRUE);
1574 glDepthFunc(GL_LEQUAL);
1577 if(anim&(ANIM_TRANSLUCENT|ANIM_SHADOW) && !enablealphablend)
1579 glEnable(GL_BLEND);
1580 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1581 enablealphablend = true;
1584 render(anim, varseed, speed, basetime, pitch, vec(0, -1, 0), d, a, rdir, campos, fogplane);
1586 if(anim&ANIM_ENVMAP)
1588 if(renderpath==R_FIXEDFUNCTION) glActiveTexture_(GL_TEXTURE0_ARB+envmaptmu);
1589 glMatrixMode(GL_TEXTURE);
1590 glLoadIdentity();
1591 glMatrixMode(GL_MODELVIEW);
1592 if(renderpath==R_FIXEDFUNCTION) glActiveTexture_(GL_TEXTURE0_ARB);
1595 if(anim&ANIM_TRANSLUCENT) glDepthFunc(GL_LESS);
1597 glPopMatrix();
1599 if(d) d->lastrendered = lastmillis;
1602 static bool enabletc, enablemtc, enablealphatest, enablealphablend, enableenvmap, enableglow, enablelighting, enablecullface, enablefog;
1603 static vec lightcolor;
1604 static plane refractfogplane;
1605 static float lastalphatest;
1606 static void *lastvbuf, *lasttcbuf, *lastmtcbuf;
1607 static GLuint lastebuf, lastenvmaptex, closestenvmaptex;
1608 static Texture *lasttex, *lastmasks, *lastnormalmap;
1609 static int envmaptmu, fogtmu;
1611 void startrender()
1613 enabletc = enablemtc = enablealphatest = enablealphablend = enableenvmap = enableglow = enablelighting = enablefog = false;
1614 enablecullface = true;
1615 lastalphatest = -1;
1616 lastvbuf = lasttcbuf = lastmtcbuf = NULL;
1617 lastebuf = lastenvmaptex = closestenvmaptex = 0;
1618 lasttex = lastmasks = lastnormalmap = NULL;
1619 envmaptmu = fogtmu = -1;
1621 static bool initlights = false;
1622 if(renderpath==R_FIXEDFUNCTION && lightmodels && !initlights)
1624 glEnable(GL_LIGHT0);
1625 static const GLfloat zero[4] = { 0, 0, 0, 0 };
1626 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, zero);
1627 glLightfv(GL_LIGHT0, GL_SPECULAR, zero);
1628 glMaterialfv(GL_FRONT, GL_SPECULAR, zero);
1629 glMaterialfv(GL_FRONT, GL_EMISSION, zero);
1630 initlights = true;
1634 static void disablemtc()
1636 glClientActiveTexture_(GL_TEXTURE1_ARB);
1637 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1638 glClientActiveTexture_(GL_TEXTURE0_ARB);
1639 enablemtc = false;
1642 static void disabletc()
1644 glDisableClientState(GL_TEXTURE_COORD_ARRAY);
1645 glDisableClientState(GL_NORMAL_ARRAY);
1646 if(enablemtc) disablemtc();
1647 enabletc = false;
1650 static void disablevbo()
1652 if(hasVBO)
1654 glBindBuffer_(GL_ARRAY_BUFFER_ARB, 0);
1655 glBindBuffer_(GL_ELEMENT_ARRAY_BUFFER_ARB, 0);
1657 glDisableClientState(GL_VERTEX_ARRAY);
1658 if(enabletc) disabletc();
1659 lastvbuf = lasttcbuf = lastmtcbuf = NULL;
1660 lastebuf = 0;
1663 static void disableglow()
1665 resettmu(0);
1666 glActiveTexture_(GL_TEXTURE1_ARB);
1667 resettmu(1);
1668 glDisable(GL_TEXTURE_2D);
1669 glActiveTexture_(GL_TEXTURE0_ARB);
1670 lasttex = lastmasks = NULL;
1671 enableglow = false;
1674 static void disablefog(bool cleanup = false)
1676 glActiveTexture_(GL_TEXTURE0_ARB+fogtmu);
1677 if(enablefog) glDisable(GL_TEXTURE_1D);
1678 if(cleanup)
1680 resettmu(fogtmu);
1681 glDisable(GL_TEXTURE_GEN_S);
1682 fogtmu = -1;
1684 glActiveTexture_(GL_TEXTURE0_ARB);
1685 enablefog = false;
1688 static void disableenvmap(bool cleanup = false)
1690 glActiveTexture_(GL_TEXTURE0_ARB+envmaptmu);
1691 if(enableenvmap) glDisable(GL_TEXTURE_CUBE_MAP_ARB);
1692 if(cleanup && renderpath==R_FIXEDFUNCTION)
1694 resettmu(envmaptmu);
1695 glDisable(GL_TEXTURE_GEN_S);
1696 glDisable(GL_TEXTURE_GEN_T);
1697 glDisable(GL_TEXTURE_GEN_R);
1699 glActiveTexture_(GL_TEXTURE0_ARB);
1700 enableenvmap = false;
1703 void endrender()
1705 if(lastvbuf || lastebuf) disablevbo();
1706 if(enablealphatest) glDisable(GL_ALPHA_TEST);
1707 if(enablealphablend) glDisable(GL_BLEND);
1708 if(enableglow) disableglow();
1709 if(enablelighting) glDisable(GL_LIGHTING);
1710 if(lastenvmaptex) disableenvmap(true);
1711 if(!enablecullface) glEnable(GL_CULL_FACE);
1712 if(fogtmu>=0) disablefog(true);
1716 bool vertmodel::enabletc = false, vertmodel::enablemtc = false, vertmodel::enablealphatest = false, vertmodel::enablealphablend = false,
1717 vertmodel::enableenvmap = false, vertmodel::enableglow = false, vertmodel::enablelighting = false, vertmodel::enablecullface = true,
1718 vertmodel::enablefog = false;
1719 vec vertmodel::lightcolor;
1720 plane vertmodel::refractfogplane;
1721 float vertmodel::lastalphatest = -1;
1722 void *vertmodel::lastvbuf = NULL, *vertmodel::lasttcbuf = NULL, *vertmodel::lastmtcbuf = NULL;
1723 GLuint vertmodel::lastebuf = 0, vertmodel::lastenvmaptex = 0, vertmodel::closestenvmaptex = 0;
1724 Texture *vertmodel::lasttex = NULL, *vertmodel::lastmasks = NULL, *vertmodel::lastnormalmap = NULL;
1725 int vertmodel::envmaptmu = -1, vertmodel::fogtmu = -1;