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
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
20 fr1
= fr1
%as
.range
+as
.frame
;
22 if(fr2
>=as
.frame
+as
.range
) fr2
= as
.frame
;
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]; };
53 Texture
*tex
, *masks
, *envmap
, *unlittex
, *normalmap
;
56 float spec
, ambient
, glow
, fullbright
, envmapmin
, envmapmax
, translucency
, scrollu
, scrollv
, alphatest
;
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
)
71 if(enablelighting
) { glDisable(GL_LIGHTING
); enablelighting
= false; }
73 else if(lightmodels
&& !enablelighting
) { glEnable(GL_LIGHTING
); enablelighting
= true; }
75 if(refracting
&& refractfog
)
77 needsfog
= masked
? 2 : 1;
78 if(fogtmu
!=needsfog
&& fogtmu
>=0) disablefog(true);
80 if(masked
!=enableglow
) lasttex
= lastmasks
= NULL
;
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
);
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
);
116 if(enableglow
) disableglow();
117 if(fullbright
) glColor4f(fullbright
, fullbright
, fullbright
, as
.anim
&ANIM_TRANSLUCENT
? translucency
: 1);
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);
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");
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
);
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);
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) \
186 static Shader *name##shader = NULL; \
187 if(!name##shader) name##shader = lookupshaderbyname(#name); \
188 name##shader->set(); \
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);
230 Texture
*s
= bumpmapped() && unlittex
? unlittex
: tex
, *m
= masks
, *n
= bumpmapped() ? normalmap
: NULL
;
233 Slot
&slot
= lookuptexture(override
);
235 if(slot
.sts
.length() >= 2)
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))
245 setshader(as
, m
!=notexture
);
248 if(enableglow
) glActiveTexture_(GL_TEXTURE1_ARB
);
249 glBindTexture(GL_TEXTURE_2D
, s
->gl
);
250 if(enableglow
) glActiveTexture_(GL_TEXTURE0_ARB
);
253 if(n
&& n
!=lastnormalmap
)
255 glActiveTexture_(GL_TEXTURE3_ARB
);
256 glBindTexture(GL_TEXTURE_2D
, n
->gl
);
257 glActiveTexture_(GL_TEXTURE0_ARB
);
263 if(!enablealphablend
&& !reflecting
&& !refracting
)
266 glBlendFunc(GL_SRC_ALPHA
, GL_ONE_MINUS_SRC_ALPHA
);
267 enablealphablend
= true;
270 else if(enablealphablend
) { glDisable(GL_BLEND
); enablealphablend
= false; }
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; }
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
);
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
);
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
);
314 if(lastenvmaptex
!=emtex
) { glBindTexture(GL_TEXTURE_CUBE_MAP_ARB
, emtex
); lastenvmaptex
= emtex
; }
315 glActiveTexture_(GL_TEXTURE0_ARB
);
318 else if(enableenvmap
) disableenvmap();
332 vbocacheentry() : vdata(NULL
), vbuf(0) { cur
.fr1
= prev
.fr1
= -1; }
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)
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
));
371 m
.tris
= new tri
[numtris
];
372 memcpy(m
.tris
, tris
, numtris
*sizeof(tri
));
375 m
.bumpverts
= new bumpvert
[numverts
];
376 memcpy(m
.bumpverts
, bumpverts
, numverts
*sizeof(bumpvert
));
378 else m
.bumpverts
= NULL
;
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
];
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
);
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
;
409 u
.mul(v2
).sub(vec(e2
).mul(v1
)).mul(scale
);
410 v
.mul(u1
).sub(vec(e1
).mul(u2
)).mul(scale
);
414 tangent
[t
.vert
[j
]].add(u
);
415 bitangent
[t
.vert
[j
]].add(v
);
418 bumpvert
*fbumpverts
= &bumpverts
[k
*numverts
];
421 const vec
&n
= fverts
[i
].norm
,
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;
432 void calcbb(int frame
, vec
&bbmin
, vec
&bbmax
, float m
[12])
434 vert
*fverts
= &verts
[frame
*numverts
];
437 vec
&v
= fverts
[j
].pos
;
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
];
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
;
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];
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
)
497 static inline void assignvert(vvert
&vv
, int j
, tcvert
&tc
, vert
&v
)
505 inline void assignvert(vvertbump
&vv
, int j
, tcvert
&tc
, vert
&v
)
511 vv
.tangent
= bumpverts
[j
].tangent
;
512 vv
.bitangent
= bumpverts
[j
].bitangent
;
516 int genvbo(vector
<ushort
> &idxs
, int offset
, vector
<T
> &vverts
)
519 eoffset
= idxs
.length();
526 tcvert
&tc
= tcverts
[t
.vert
[j
]];
527 vert
&v
= verts
[t
.vert
[j
]];
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
);
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
)
546 eoffset
= idxs
.length();
550 loopj(3) idxs
.add(voffset
+t
.vert
[j
]);
553 maxvert
= voffset
+ numverts
-1;
554 elen
= idxs
.length()-eoffset
;
558 void filltc(uchar
*vdata
, size_t stride
)
560 vdata
= (uchar
*)&((vvertff
*)&vdata
[voffset
*stride
])->u
;
563 *(tcvert
*)vdata
= tcverts
[i
];
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) \
586 type &v = ((type *)vdata)[i]; \
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
; })
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
)
610 void render(animstate
&as
, anpos
&cur
, anpos
*prev
, float ai_t
, skin
&s
, vbocacheentry
&vc
)
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
;
631 else if(enablemtc
) disablemtc();
633 if(renderpath
==R_FIXEDFUNCTION
&& (s
.scrollu
|| s
.scrollv
))
635 glMatrixMode(GL_TEXTURE
);
637 glTranslatef(s
.scrollu
*lastmillis
/1000.0f
, s
.scrollv
*lastmillis
/1000.0f
, 0);
639 if(s
.multitextured())
641 glActiveTexture_(GL_TEXTURE1_ARB
);
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
]);
651 xtravertsva
+= numverts
;
653 if(renderpath
==R_FIXEDFUNCTION
&& (s
.scrollu
|| s
.scrollv
))
655 if(s
.multitextured())
658 glActiveTexture_(GL_TEXTURE0_ARB
);
662 glMatrixMode(GL_MODELVIEW
);
673 float transform
[3][3];
675 tag() : name(NULL
) {}
676 ~tag() { DELETEA(name
); }
684 vector
<mesh
*> meshes
;
686 int numtags
, numframes
;
690 static const int MAXVBOCACHE
= 8;
691 vbocacheentry vbocache
[MAXVBOCACHE
];
695 bool vnorms
, vtangents
;
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
)
706 meshes
.deletecontentsp();
708 if(ebuf
) glDeleteBuffers_(1, &ebuf
);
711 DELETEA(vbocache
[i
].vdata
);
712 if(vbocache
[i
].vbuf
) glDeleteBuffers_(1, &vbocache
[i
].vbuf
);
718 int findtag(const char *name
)
720 loopi(numtags
) if(!strcmp(tags
[i
].name
, name
)) return i
;
724 vec
anyvert(int frame
)
726 loopv(meshes
) if(meshes
[i
]->numverts
) return meshes
[i
]->verts
[frame
*meshes
[i
]->numverts
].pos
;
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
); }
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
;
755 group
.translate
= translate
;
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
);
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
);
778 translate
= ntranslate
;
783 void concattagtransform(int frame
, int i
, float m
[12], float n
[12])
785 tag
&t
= tags
[frame
*numtags
+ i
];
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)
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
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
819 matrix
[3] = matrix
[7] = matrix
[11] = 0.0f
;
823 void genvbo(bool norms
, bool tangents
, vbocacheentry
&vc
)
827 if(!vc
.vbuf
) glGenBuffers_(1, &vc
.vbuf
);
832 #define ALLOCVDATA(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); \
840 if(!vc
.vdata
) ALLOCVDATA(vc
.vdata
);
847 vtangents
= tangents
;
851 loopv(meshes
) vlen
+= meshes
[i
]->genvbo(idxs
, vlen
);
853 if(hasVBO
) ALLOCVDATA(vdata
);
854 else ALLOCVDATA(vc
.vdata
);
858 if(hasVBO
) glBindBuffer_(GL_ARRAY_BUFFER_ARB
, vc
.vbuf
);
859 #define GENVBO(type) \
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); \
868 vc.vdata = new uchar[vverts.length()*sizeof(type)]; \
869 memcpy(vc.vdata, vverts.getbuf(), vverts.length()*sizeof(type)); \
872 if(tangents
) GENVBO(vvertbump
);
873 else if(norms
) GENVBO(vvert
);
874 else GENVBO(vvertff
);
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
);
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
);
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
;
924 void render(animstate
&as
, anpos
&cur
, anpos
*prev
, float ai_t
, vector
<skin
> &skins
)
926 bool norms
= false, tangents
= false;
929 if(skins
[i
].normals()) norms
= true;
930 if(skins
[i
].tangents()) tangents
= true;
932 if(norms
!=vnorms
|| tangents
!=vtangents
)
936 vbocacheentry
&c
= vbocache
[i
];
937 if(c
.vbuf
) { glDeleteBuffers_(1, &c
.vbuf
); c
.vbuf
= 0; }
941 if(hasVBO
) { if(ebuf
) { glDeleteBuffers_(1, &ebuf
); ebuf
= 0; } }
943 lastvbuf
= lasttcbuf
= lastmtcbuf
= NULL
;
946 vbocacheentry
*vc
= NULL
;
947 if(numframes
<=1) vc
= vbocache
;
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
);
961 if(vc
->cur
!=cur
|| (prev
? vc
->prev
!=*prev
|| vc
->t
!=ai_t
: vc
->prev
.fr1
>=0))
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
));
970 mesh
&m
= *meshes
[i
];
971 m
.interpverts(cur
, prev
, ai_t
, norms
, tangents
, (hasVBO
? vdata
: vc
->vdata
) + m
.voffset
*vertsize
, skins
[i
]);
975 glBindBuffer_(GL_ARRAY_BUFFER_ARB
, vc
->vbuf
);
976 glBufferData_(GL_ARRAY_BUFFER_ARB
, vlen
*vertsize
, vdata
, GL_STREAM_DRAW_ARB
);
982 loopv(meshes
) meshes
[i
]->render(as
, cur
, prev
, ai_t
, skins
[i
], *vc
);
998 linkedpart() : p(NULL
), anim(-1), basetime(0) {}
1006 vector
<linkedpart
> links
;
1008 vector
<animinfo
> *anims
;
1009 float pitchscale
, pitchoffset
, pitchmin
, pitchmax
;
1011 part() : meshes(NULL
), anims(NULL
), pitchscale(1), pitchoffset(0), pitchmin(0), pitchmax(0) {}
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
)
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
)
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();
1057 links
[i
].anim
= anim
;
1058 links
[i
].basetime
= basetime
;
1062 void initskins(Texture
*tex
= notexture
, Texture
*masks
= notexture
)
1065 while(skins
.length() < meshes
->meshes
.length())
1067 skin
&s
= skins
.add();
1074 virtual void getdefaultanim(animstate
&as
, int anim
, int varseed
, dynent
*d
)
1080 void getanimspeed(animstate
&as
, dynent
*d
)
1082 switch(as
.anim
&ANIM_INDEX
)
1089 as
.speed
= 5500.0f
/d
->maxspeed
;
1098 bool calcanimstate(int anim
, int varseed
, float speed
, int basetime
, dynent
*d
, animstate
&as
)
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;
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
);
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;
1165 void calcnormal(GLfloat
*m
, vec
&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];
1179 void calcvertex(GLfloat
*m
, vec
&pos
)
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
;
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];
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
);
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
);
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
)
1227 if(!calcanimstate(anim
, varseed
, speed
, basetime
, d
, as
)) return;
1230 cur
.setframes(d
&& index
<2 ? d
->current
[index
] : as
);
1233 bool doai
= d
&& index
<2 && lastmillis
-d
->lastanimswitchtime
[index
]<animationinterpolationtime
&& d
->prev
[index
].range
>0;
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
);
1249 glRotatef(pitchamount
, axis
.x
, axis
.y
, axis
.z
);
1250 if(renderpath
!=R_FIXEDFUNCTION
&& anim
&ANIM_ENVMAP
)
1252 glMatrixMode(GL_TEXTURE
);
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);
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
);
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
;
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
);
1299 glMultMatrixf(matrix
);
1300 if(renderpath
!=R_FIXEDFUNCTION
&& anim
&ANIM_ENVMAP
)
1302 glMatrixMode(GL_TEXTURE
);
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
);
1318 glMatrixMode(GL_MODELVIEW
);
1326 if(renderpath
!=R_FIXEDFUNCTION
&& anim
&ANIM_ENVMAP
)
1328 glMatrixMode(GL_TEXTURE
);
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
);
1342 if(!anims
) anims
= new vector
<animinfo
>[NUMANIMS
];
1343 animinfo
&ai
= anims
[num
].add();
1347 ai
.priority
= priority
;
1353 vector
<part
*> parts
;
1355 vertmodel(const char *name
) : loaded(false)
1357 loadname
= newstring(name
);
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
);
1391 vector
<BIH::tri
> tris
;
1393 bih
= new BIH(tris
.length(), tris
.getbuf());
1397 void calcbb(int frame
, vec
¢er
, vec
&radius
)
1399 if(parts
.empty()) return;
1401 bbmin
= bbmax
= parts
[0]->meshes
->anyvert(frame
);
1402 parts
[0]->calcbb(frame
, bbmin
, bbmax
);
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;
1416 void setskin(int tex
= 0)
1418 loopv(parts
) loopvj(parts
[i
]->skins
) parts
[i
]->skins
[j
].override
= tex
;
1423 loopv(parts
) loopvj(parts
[i
]->skins
) if(parts
[i
]->skins
[j
].envmapped()) return true;
1427 virtual bool loaddefaultparts()
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
];
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
)
1504 yaw
+= spin
*lastmillis
/1000.0f
;
1506 if(!(anim
&ANIM_NOSKIN
))
1508 fogplane
= plane(0, 0, 1, o
.z
-refracting
);
1513 rdir
.rotate_around_z((-yaw
-180.0f
)*RAD
);
1515 campos
= camera1
->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
;
1525 if(anim
&ANIM_ENVMAP
) closestenvmaptex
= lookupenvmap(closestenvmap(o
));
1528 if(anim
&ANIM_ENVMAP
)
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
];
1551 glLoadMatrixf(mmtrans
);
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
);
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
)
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
);
1591 glMatrixMode(GL_MODELVIEW
);
1592 if(renderpath
==R_FIXEDFUNCTION
) glActiveTexture_(GL_TEXTURE0_ARB
);
1595 if(anim
&ANIM_TRANSLUCENT
) glDepthFunc(GL_LESS
);
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
;
1613 enabletc
= enablemtc
= enablealphatest
= enablealphablend
= enableenvmap
= enableglow
= enablelighting
= enablefog
= false;
1614 enablecullface
= true;
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
);
1634 static void disablemtc()
1636 glClientActiveTexture_(GL_TEXTURE1_ARB
);
1637 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
1638 glClientActiveTexture_(GL_TEXTURE0_ARB
);
1642 static void disabletc()
1644 glDisableClientState(GL_TEXTURE_COORD_ARRAY
);
1645 glDisableClientState(GL_NORMAL_ARRAY
);
1646 if(enablemtc
) disablemtc();
1650 static void disablevbo()
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
;
1663 static void disableglow()
1666 glActiveTexture_(GL_TEXTURE1_ARB
);
1668 glDisable(GL_TEXTURE_2D
);
1669 glActiveTexture_(GL_TEXTURE0_ARB
);
1670 lasttex
= lastmasks
= NULL
;
1674 static void disablefog(bool cleanup
= false)
1676 glActiveTexture_(GL_TEXTURE0_ARB
+fogtmu
);
1677 if(enablefog
) glDisable(GL_TEXTURE_1D
);
1681 glDisable(GL_TEXTURE_GEN_S
);
1684 glActiveTexture_(GL_TEXTURE0_ARB
);
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;
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;