1 /*
2 Copyright (C) 2001-2002 Charles Hollemeersch
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18
19 PENTA: the whole file is freakin penta...
20
21 Alias instants
22
23 There are 2 types of alias instants Frame & Light.
24 -Frame is the instant that is used per frame it contains light independent information like
25 vertices, tangent space, normals ....
26 -Light is the instant that is used per light, vertex light directions, shadow volume vertices,
27 half angle vectors ....
28
29 The instants are in a basic cache system, every frame an entity gets an instant and is guaranteed to
30 have it for the rest of the frame.
31 The next frame we look if we can reuse the instant of the previous frame if this is the case we don't
32 recalculate stuff otherwise we calculate everything. So it caches interpolated
33 vertices & shadowvolumes between frames.
34
35 */
36
37 #include "quakedef.h"
38
39 #define NUM_ALIAS_INSTANTS 64
40
41 #define NUM_ALIAS_LIGHT_INSTANTS 196
42
43 aliasframeinstant_t InstantCache[NUM_ALIAS_INSTANTS];
44 aliaslightinstant_t LightInstantCache[NUM_ALIAS_LIGHT_INSTANTS];
45
46 void R_SetupInstantForFrame(entity_t *e, qboolean forcevis);
47
48
49 #define DIST_DELTA 0.1
50 #define ANG_DELTA 0.5
51 #define RADIUS_DELTA 0.1
52 #define BLEND_DELTA 0.0000001 //This lets the interpolation run at ~30fps this looks verry smooth
53 //and makes our caches usefull
54 //BLEND_DELTA = 1 means 10 fps means no interpolation visible
55
56 int aliasCacheRequests, aliasFullCacheHits, aliasPartialCacheHits;
57
58 /*
59 R_AllocateInstant
60 */
R_AllocateInstant(entity_t * e,aliasframeinstant_t * frameinstant,aliashdr_t * paliashdr)61 aliasframeinstant_t *R_AllocateInstant(entity_t *e, aliasframeinstant_t *frameinstant, aliashdr_t *paliashdr) {
62
63 int i, oldest, oindex;
64
65 /* is this frameinstant ok ? */
66 if (frameinstant)
67 if ((frameinstant->paliashdr == paliashdr)
68 && (frameinstant->lastent == e))
69 return frameinstant;
70
71 //none found, bacause we don't want to destroy the reclaiming of other ents
72 //we use the oldest used instant
73 oldest = r_framecount;
74 oindex = -1;
75 for (i=0; i<NUM_ALIAS_INSTANTS; i++) {
76 if (InstantCache[i].lockframe < oldest) {
77 oldest = InstantCache[i].lockframe;
78 oindex = i;
79 }
80 }
81
82 if (oindex == -1) {
83 //we didn't find a free one for this frame
84 return NULL;
85 }
86
87 return &InstantCache[oindex];
88 }
89
90 /*
91 R_AllocateInstant
92 */
R_AllocateLightInstant(entity_t * e,aliashdr_t * paliashdr)93 aliaslightinstant_t *R_AllocateLightInstant(entity_t *e, aliashdr_t * paliashdr) {
94
95 int i, oldest, oindex;
96 /*
97 if (InstantsUsed < NUM_ALIAS_INSTANTS ) {
98 return &InstantCache[InstantsUsed++];
99 } else {
100 return NULL;
101 }
102 */
103
104 //try to reclaim an instant that was previously used for this surface and this light
105 for (i=0; i<NUM_ALIAS_LIGHT_INSTANTS; i++) {
106 if ((LightInstantCache[i].lastent == e) && (LightInstantCache[i].lastlight == currentshadowlight) && (LightInstantCache[i].lasthdr == paliashdr))
107 return &LightInstantCache[i];
108 }
109
110 //none found, bacause we don't want to destroy the reclaiming of other ents
111 //we use the oldest used instant
112 oldest = r_framecount;
113 oindex = -1;
114 for (i=0; i<NUM_ALIAS_LIGHT_INSTANTS; i++) {
115 if (LightInstantCache[i].lockframe < oldest) {
116 oldest = LightInstantCache[i].lockframe;
117 oindex = i;
118 }
119 }
120
121 if (oindex == -1) {
122 //find an instant of an other light
123 for (i=0; i<NUM_ALIAS_LIGHT_INSTANTS; i++) {
124 if (LightInstantCache[i].lastlight != currentshadowlight)
125 return &LightInstantCache[i];
126 }
127 }
128
129 LightInstantCache[oindex].lastent = NULL;
130 LightInstantCache[oindex].lastframeinstant = NULL;
131 LightInstantCache[oindex].lastlight = NULL;
132
133 return &LightInstantCache[oindex];
134 }
135
136 /*
137 R_ClearInstants
138 */
R_ClearInstantCaches()139 void R_ClearInstantCaches() {
140
141 int i;
142
143 for (i=0; i<NUM_ALIAS_INSTANTS; i++) {
144 InstantCache[i].lockframe = 0;
145 InstantCache[i].lastent = NULL;
146 InstantCache[i].paliashdr = NULL;
147 }
148
149 for (i=0; i<NUM_ALIAS_LIGHT_INSTANTS; i++) {
150 LightInstantCache[i].lockframe = 0;
151 LightInstantCache[i].lastent = NULL;
152 LightInstantCache[i].lastlight = NULL;
153 LightInstantCache[i].lastframeinstant = NULL;
154 }
155 }
156
157 /*
158 =============
159 R_SetupInstants
160 =============
161 */
162
R_SetupInstants()163 void R_SetupInstants ()
164 {
165 int i;
166
167 if (!r_drawentities.value)
168 return;
169
170 //return;
171 for (i=0 ; i<cl_numvisedicts ; i++)
172 {
173 currententity = cl_visedicts[i];
174 if (currententity->model->type == mod_alias) {
175 R_SetupInstantForFrame(currententity,false);
176 }
177 }
178
179 if (mirror) return;
180
181 //interpolate gun also
182 if (cl.viewent.model && cl.viewent.model->type == mod_alias)
183 R_SetupInstantForFrame(&cl.viewent,true);
184
185 //for player
186 if (cl_entities[cl.viewentity].model && cl_entities[cl.viewentity].model->type == mod_alias)
187 R_SetupInstantForFrame(&cl_entities[cl.viewentity],true);
188
189 }
190
191
192 /*************************
193
194 Methods called per frame
195
196 **************************/
197
198 /*
199 R_InterpolateVerts
200 */
R_InterpolateVerts(aliashdr_t * paliashdr,aliasframeinstant_t * instant,int pose1,int pose2,float blend)201 void R_InterpolateVerts(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
202 float blend1;
203 ftrivertx_t *verts1;
204 ftrivertx_t *verts2;
205 int i;
206
207 verts1 = (ftrivertx_t *) ((byte *) paliashdr + paliashdr->posedata);
208 verts2 = verts1;
209
210 verts1 += pose1 * paliashdr->poseverts;
211 verts2 += pose2 * paliashdr->poseverts;
212
213 blend1 = 1-blend;
214
215 for (i=0; i<paliashdr->poseverts; i++) {
216 //interpolate them
217 instant->vertices[i][0] = verts1[i].v[0] * blend1 + verts2[i].v[0] * blend;
218 instant->vertices[i][1] = verts1[i].v[1] * blend1 + verts2[i].v[1] * blend;
219 instant->vertices[i][2] = verts1[i].v[2] * blend1 + verts2[i].v[2] * blend;
220 }
221 }
222
223 /*
224 R_InterpolateNormals
225 */
R_InterpolateNormals(aliashdr_t * paliashdr,aliasframeinstant_t * instant,int pose1,int pose2,float blend)226 void R_InterpolateNormals(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
227 float blend1, lat, lng;
228 ftrivertx_t *verts1;
229 ftrivertx_t *verts2;
230 vec3_t norm1, norm2;
231 int i;
232
233 verts1 = (ftrivertx_t *) ((byte *) paliashdr + paliashdr->posedata);
234 verts2 = verts1;
235
236 verts1 += pose1 * paliashdr->poseverts;
237 verts2 += pose2 * paliashdr->poseverts;
238
239 blend1 = 1-blend;
240
241 for (i=0; i<paliashdr->poseverts; i++) {
242
243 lat = ( verts1[i].lightnormalindex >> 8 ) & 0xff;
244 lng = ( verts1[i].lightnormalindex & 0xff );
245 lat *= M_PI/128;
246 lng *= M_PI/128;
247
248 norm1[0] = cos(lat) * sin(lng);
249 norm1[1] = sin(lat) * sin(lng);
250 norm1[2] = cos(lng);
251
252 lat = ( verts2[i].lightnormalindex >> 8 ) & 0xff;
253 lng = ( verts2[i].lightnormalindex & 0xff );
254 lat *= M_PI/128;
255 lng *= M_PI/128;
256
257 norm2[0] = cos(lat) * sin(lng);
258 norm2[1] = sin(lat) * sin(lng);
259 norm2[2] = cos(lng);
260
261 //interpolate them
262 instant->normals[i][0] = norm1[0] * blend1 + norm2[0] * blend;
263 instant->normals[i][1] = norm1[1] * blend1 + norm2[1] * blend;
264 instant->normals[i][2] = norm1[2] * blend1 + norm2[2] * blend;
265 VectorNormalize(instant->normals[i]);
266 }
267 }
268
269 /*
270 R_InterpolateTangents
271 */
R_InterpolateTangents(aliashdr_t * paliashdr,aliasframeinstant_t * instant,int pose1,int pose2,float blend)272 void R_InterpolateTangents(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
273 float blend1;
274 vec3_t *verts1;
275 vec3_t *verts2;
276 float *tang1, *tang2;
277 int i;
278
279 verts1 = (vec3_t *) ((byte *) paliashdr + paliashdr->tangents);
280 verts2 = verts1;
281
282 verts1 += pose1 * paliashdr->poseverts;
283 verts2 += pose2 * paliashdr->poseverts;
284
285 blend1 = 1-blend;
286
287 for (i=0; i<paliashdr->poseverts; i++) {
288
289 tang1 = (float *)&verts1[i];
290 tang2 = (float *)&verts2[i];
291
292 //interpolate them
293 instant->tangents[i][0] = tang1[0] * blend1 + tang2[0] * blend;
294 instant->tangents[i][1] = tang1[1] * blend1 + tang2[1] * blend;
295 instant->tangents[i][2] = tang1[2] * blend1 + tang2[2] * blend;
296 }
297 }
298
299 /*
300 R_InterpolateBinomials
301 */
R_InterpolateBinomials(aliashdr_t * paliashdr,aliasframeinstant_t * instant,int pose1,int pose2,float blend)302 void R_InterpolateBinomials(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
303 float blend1;
304 vec3_t *verts1;
305 vec3_t *verts2;
306 float *binor1, *binor2;
307 int i;
308
309 if (paliashdr->binormals == 0) return;
310
311 verts1 = (vec3_t *) ((byte *) paliashdr + paliashdr->binormals);
312 verts2 = verts1;
313
314 verts1 += pose1 * paliashdr->poseverts;
315 verts2 += pose2 * paliashdr->poseverts;
316
317 blend1 = 1-blend;
318
319 for (i=0; i<paliashdr->poseverts; i++) {
320
321 binor1 = (float *)&verts1[i];
322 binor2 = (float *)&verts2[i];
323
324 //interpolate them
325 instant->binomials[i][0] = binor1[0] * blend1 + binor2[0] * blend;
326 instant->binomials[i][1] = binor1[1] * blend1 + binor2[1] * blend;
327 instant->binomials[i][2] = binor1[2] * blend1 + binor2[2] * blend;
328 }
329 }
330
331 /*
332 R_InterpolateTriPlanes
333 */
R_InterpolateTriPlanes(aliashdr_t * paliashdr,aliasframeinstant_t * instant,int pose1,int pose2,float blend)334 void R_InterpolateTriPlanes(aliashdr_t *paliashdr, aliasframeinstant_t *instant, int pose1, int pose2, float blend) {
335 float blend1;
336 plane_t *planes1, *planes2;
337 int i;
338
339 planes1 = (plane_t *)((byte *)paliashdr + paliashdr->planes);
340 planes2 = planes1;
341 planes1 += pose1 * paliashdr->numtris;
342 planes2 += pose2 * paliashdr->numtris;
343
344 blend1 = 1-blend;
345
346 for (i=0; i<paliashdr->numtris; i++) {
347 instant->triplanes[i].normal[0] = planes1[i].normal[0] * blend1 + planes2[i].normal[0] * blend;
348 instant->triplanes[i].normal[1] = planes1[i].normal[1] * blend1 + planes2[i].normal[1] * blend;
349 instant->triplanes[i].normal[2] = planes1[i].normal[2] * blend1 + planes2[i].normal[2] * blend;
350 instant->triplanes[i].dist = planes1[i].dist * blend1 + planes2[i].dist * blend;
351 }
352 }
353
354 /*
355 R_SetupLerpPoses
356
357 Lerp frame code
358 From QuakeForge
359
360 This determines the two frames to interpolate inbetween an calculates the blending factor
361
362 */
R_SetupLerpPoses(aliashdr_t * paliashdr,entity_t * e)363 void R_SetupLerpPoses(aliashdr_t *paliashdr,entity_t *e) {
364 int frame, pose, numposes;
365 float blend;
366
367 frame = e->frame;
368
369 if ((frame >= paliashdr->numframes) || (frame < 0)) {
370 Con_DPrintf ("R_SetupLerpPoses: no such frame %d\n", frame);
371 frame = 0;
372 }
373
374 pose = paliashdr->frames[frame].firstpose;
375 numposes = paliashdr->frames[frame].numposes;
376
377 if (numposes > 1) {
378 e->frame_interval = paliashdr->frames[frame].interval;
379 pose += (int) (cl.time / e->frame_interval) % numposes;
380 } else {
381 /*
382 One tenth of a second is a good for most Quake animations. If the
383 nextthink is longer then the animation is usually meant to pause
384 (e.g. check out the shambler magic animation in shambler.qc). If
385 its shorter then things will still be smoothed partly, and the
386 jumps will be less noticable because of the shorter time. So,
387 this is probably a good assumption.
388 */
389 e->frame_interval = 0.1;
390 }
391
392 if (e->pose2 != pose) {
393 e->frame_start_time = realtime;
394 if (e->pose2 == -1) {
395 e->pose1 = pose;
396 } else {
397 e->pose1 = e->pose2;
398 }
399 e->pose2 = pose;
400 blend = 0;
401 } else {
402 blend = (realtime - e->frame_start_time) / e->frame_interval;
403 }
404
405 // wierd things start happening if blend passes 1
406 if (cl.paused || blend > 1)
407 blend = 1;
408
409 if ((e->pose1 >= paliashdr->numposes) || (e->pose1 < 0)) {
410 Con_DPrintf ("R_SetupLerpPoses: invalid pose %d\n", e->pose1);
411 e->pose1 = 0;
412 }
413
414
415 if ((e->pose2 >= paliashdr->numposes) || (e->pose2 < 0)) {
416 Con_DPrintf ("R_SetupLerpPoses: invalid pose %d\n", e->pose2);
417 e->pose2 = 0;
418 }
419
420 e->blend = blend;
421 }
422
423 /*
424 Returns true if the status has changed enough to recalculate the interpolations.
425 */
426
CheckUpdate(entity_t * e,aliasframeinstant_t * ins)427 qboolean CheckUpdate(entity_t *e, aliasframeinstant_t *ins) {
428
429 if (sh_nocache.value) return true;
430
431 if ((ins->lastent == e) &&
432 (ins->lastpose1 == e->pose1) &&
433 (ins->lastpose2 == e->pose2) &&
434 ( (fabs(ins->lastblend - e->blend) <= BLEND_DELTA) || (e->pose1 == e->pose2) ) &&
435 (ins->lastshadowonly == ins->shadowonly) &&
436 (ins->lastpaliashdr == ins->paliashdr) &&
437 (ins->lockframe >= r_framecount-10))//XYW Don't reuse if it has been unused for a long time
438 {
439 return false;
440 } else {
441 return true;
442 }
443
444 //return true;
445 }
446
447
R_SetupAliasInstantForFrame(entity_t * e,qboolean forcevis,aliashdr_t * paliashdr,aliasframeinstant_t * aliasframeinstant)448 void R_SetupAliasInstantForFrame(entity_t *e, qboolean forcevis, aliashdr_t *paliashdr, aliasframeinstant_t *aliasframeinstant)
449 {
450 vec3_t mins, maxs;
451
452 if (!forcevis) {
453
454
455 if (e->angles[0] || e->angles[1] || e->angles[2])
456 {
457 int i;
458 for (i=0 ; i<3 ; i++)
459 {
460 mins[i] = e->origin[i] - e->model->radius;
461 maxs[i] = e->origin[i] + e->model->radius;
462 }
463 } else {
464 VectorAdd (e->origin,e->model->mins, mins);
465 VectorAdd (e->origin,e->model->maxs, maxs);
466 }
467
468 if (R_CullBox (mins, maxs))
469 aliasframeinstant->shadowonly = true;
470 else
471 aliasframeinstant->shadowonly = false;
472 } else aliasframeinstant->shadowonly = false;
473
474 aliasframeinstant->paliashdr = paliashdr;
475 R_SetupLerpPoses(paliashdr, e);
476
477 //see if an update is needed
478 if (CheckUpdate(e, aliasframeinstant)) {
479 R_InterpolateVerts(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
480 if (!aliasframeinstant->shadowonly) {
481 R_InterpolateNormals(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
482 R_InterpolateTangents(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
483 R_InterpolateBinomials(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
484 }
485 R_InterpolateTriPlanes(paliashdr, aliasframeinstant, e->pose1, e->pose2, e->blend);
486 aliasframeinstant->updateframe = r_framecount;
487
488 //make sure that we can compare the next frame
489 aliasframeinstant->lastpose1 = e->pose1;
490 aliasframeinstant->lastpose2 = e->pose2;
491 aliasframeinstant->lastblend = e->blend;
492 aliasframeinstant->lastshadowonly = aliasframeinstant->shadowonly;
493 aliasframeinstant->lastent = e;
494 aliasframeinstant->lastpaliashdr = aliasframeinstant->paliashdr;
495 }
496
497 //lock it for this frame
498 aliasframeinstant->lockframe = r_framecount;
499 }
500
501
R_SetupInstantForFrame(entity_t * e,qboolean forcevis)502 void R_SetupInstantForFrame(entity_t *e, qboolean forcevis)
503 {
504 alias3data_t *data;
505 aliashdr_t *paliashdr;
506 aliasframeinstant_t *aliasframeinstant;
507 aliasframeinstant_t *nextframeinstant;
508 aliasframeinstant_t *prevframeinstant;
509 int numsurf,maxnumsurf;
510
511
512 data = (alias3data_t *)Mod_Extradata (e->model);
513 maxnumsurf = data->numSurfaces;
514
515 /* first surface */
516
517 paliashdr = (aliashdr_t *)((char*)data + data->ofsSurfaces[0]);
518 e->aliasframeinstant = prevframeinstant = aliasframeinstant = R_AllocateInstant (e,e->aliasframeinstant,paliashdr);
519
520 if (aliasframeinstant)
521 R_SetupAliasInstantForFrame(e,forcevis,paliashdr,aliasframeinstant);
522 else
523 Con_Printf("Could Not Allocate Instant\n");
524
525
526 /* the other surfaces */
527 for (numsurf=1;numsurf < maxnumsurf ; ++numsurf){
528
529 paliashdr = (aliashdr_t *)((char*)data + data->ofsSurfaces[numsurf]);
530 // follow the instant chain
531 if (aliasframeinstant)
532 nextframeinstant = aliasframeinstant->_next;
533
534 aliasframeinstant = R_AllocateInstant (e,aliasframeinstant,paliashdr);
535
536 if (!aliasframeinstant) {
537 Con_Printf("Could Not Allocate Instant\n");
538 continue;
539 }
540 prevframeinstant->_next = aliasframeinstant;
541 prevframeinstant = aliasframeinstant;
542
543 R_SetupAliasInstantForFrame(e,forcevis,paliashdr,aliasframeinstant);
544
545 aliasframeinstant = nextframeinstant;
546
547 } /* for paliashdr */
548
549 //prevframeinstant->_next = NULL;
550 }
551
552
553 /*************************
554
555 Methods called per light
556
557 **************************/
558
R_SetupObjectSpace(entity_t * e,aliaslightinstant_t * linstant)559 void R_SetupObjectSpace(entity_t *e, aliaslightinstant_t *linstant) {
560
561 matrix_4x4 transf;
562 float org[4], res[4];
563
564 //Put light & view origin into object space
565 R_WorldToObjectMatrix(e, transf);
566 org[0] = currentshadowlight->origin[0];
567 org[1] = currentshadowlight->origin[1];
568 org[2] = currentshadowlight->origin[2];
569 org[3] = 1;
570 Mat_Mul_1x4_4x4(org,transf,res);
571 linstant->lightpos[0] = res[0];
572 linstant->lightpos[1] = res[1];
573 linstant->lightpos[2] = res[2];
574
575 org[0] = r_refdef.vieworg[0];
576 org[1] = r_refdef.vieworg[1];
577 org[2] = r_refdef.vieworg[2];
578 org[3] = 1;
579 Mat_Mul_1x4_4x4(org,transf,res);
580 linstant->vieworg[0] = res[0];
581 linstant->vieworg[1] = res[1];
582 linstant->vieworg[2] = res[2];
583 }
584
R_SetupLightHAV(aliasframeinstant_t * instant,aliaslightinstant_t * linstant)585 void R_SetupLightHAV(aliasframeinstant_t *instant, aliaslightinstant_t *linstant) {
586 int i;
587 vec3_t lightDir, H, tx, ty, tz;
588
589 for (i=0; i<instant->paliashdr->poseverts; i++) {
590
591 //Calc binominal
592 VectorCopy(instant->normals[i],tz);
593 VectorCopy(instant->tangents[i],ty);
594 VectorCopy(instant->binomials[i],tx);
595
596 //Calculate local light vector and put it into tangent space
597 VectorSubtract(linstant->lightpos, instant->vertices[i], lightDir);
598
599 linstant->tslights[i][0] = DotProduct(lightDir,tx);
600 linstant->tslights[i][1] = -DotProduct(lightDir,ty);
601 linstant->tslights[i][2] = DotProduct(lightDir,tz);
602
603 //Calculate local H vector and put it into tangent space
604 VectorNormalize(lightDir);
605 VectorSubtract(linstant->vieworg, instant->vertices[i], H);
606 VectorNormalize(H);
607 VectorAdd(lightDir,H,H);
608
609 linstant->tshalfangles[i][0] = DotProduct(H,tx);
610 linstant->tshalfangles[i][1] = -DotProduct(H,ty);
611 linstant->tshalfangles[i][2] = DotProduct(H,tz);
612 }
613 }
614
615 extern int extrudeTimeStamp; // <AWE> added "extern".
616 extern int extrudedTimestamp[MAXALIASVERTS]; //PENTA: Temp buffer for extruded vertices
617 // <AWE> added "extern".
618
R_CalcVolumeVerts(aliasframeinstant_t * instant,aliaslightinstant_t * linstant)619 void R_CalcVolumeVerts(aliasframeinstant_t *instant, aliaslightinstant_t *linstant) {
620
621 mtriangle_t *tris, *triangle;
622 float d, scale;
623 int i, j;
624 vec3_t v2, *v1;
625 aliashdr_t *paliashdr = instant->paliashdr;
626
627 tris = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
628
629 extrudeTimeStamp++;
630
631 //calculate visibility
632 for (i=0; i<paliashdr->numtris; i++) {
633 d = DotProduct(instant->triplanes[i].normal, linstant->lightpos) - instant->triplanes[i].dist;
634 if (d > 0)
635 linstant->triangleVis[i] = true;
636 else
637 linstant->triangleVis[i] = false;
638 }
639
640 if (!currentshadowlight->castShadow) return;
641
642 //extude vertices
643 triangle = tris;
644 for (i=0; i<paliashdr->numtris; i++, triangle++) {
645
646 if (linstant->triangleVis[i]) {//extrude it!
647
648 //for all verts
649 for (j=0; j<3; j++) {
650
651 int index = triangle->vertindex[j];
652
653 //vertex was already extruded for another triangle?
654 if (extrudedTimestamp[index] == extrudeTimeStamp) continue;
655 extrudedTimestamp[index] = extrudeTimeStamp;
656
657 v1 = &linstant->extvertices[index];
658
659 VectorCopy(instant->vertices[index],v2);
660
661 VectorSubtract (v2, linstant->lightpos, (*v1));
662 scale = Length ((*v1));
663
664 if (sh_visiblevolumes.value) {
665 //make them short so that we see them
666 VectorScale ((*v1), (1/scale)* 70, (*v1));
667 } else {
668 //we don't have to be afraid they will clip with the far plane
669 //since we use the infinite matrix trick
670 VectorScale ((*v1), (1/scale)* currentshadowlight->radius*10, (*v1));
671 }
672 VectorAdd ((*v1), v2 ,(*v1));
673 }
674 }
675 }
676 }
677
R_CalcAttenColors(aliasframeinstant_t * instant,aliaslightinstant_t * linstant)678 void R_CalcAttenColors(aliasframeinstant_t *instant, aliaslightinstant_t *linstant)
679 {
680 vec3_t *v, diff;
681 float distsq, fallOff;
682 float radiussq = currentshadowlight->radius*currentshadowlight->radius;
683 int i;
684
685 for (i=0; i<instant->paliashdr->poseverts; i++) {
686 v = &instant->vertices[i];
687 VectorSubtract(*v,linstant->lightpos,diff);
688 distsq = DotProduct(diff,diff);
689 fallOff = (radiussq - distsq) / radiussq;
690 if (fallOff < 0) fallOff = 0;
691 fallOff *= fallOff;
692 linstant->colors[i][0] = fallOff;
693 linstant->colors[i][1] = fallOff;
694 linstant->colors[i][2] = fallOff;
695 }
696 }
697
698
R_CalcIndeciesForLight(aliasframeinstant_t * instant,aliaslightinstant_t * linstant)699 void R_CalcIndeciesForLight(aliasframeinstant_t *instant, aliaslightinstant_t *linstant) {
700
701 mtriangle_t *tris;
702 int i, j;
703 int *indecies;
704 aliashdr_t *paliashdr = instant->paliashdr;
705 indecies = (int *)((byte *)paliashdr + paliashdr->indecies);
706 tris = (mtriangle_t *)((byte *)paliashdr + paliashdr->triangles);
707 /*
708 //calculate visibility
709 linstant->numtris = paliashdr->numtris;
710 for (i=0; i<paliashdr->numtris; i++) {
711 linstant->indecies[i*3] = indecies[i*3];
712 linstant->indecies[i*3+1] = indecies[i*3+1];
713 linstant->indecies[i*3+2] = indecies[i*3+2];
714 }
715
716 return;
717 */
718
719 j = 0;
720 linstant->numtris = 0;
721 for (i=0; i<paliashdr->numtris; i++) {
722 if (!linstant->triangleVis[i]) {
723 linstant->numtris++;
724 linstant->indecies[j] = indecies[i*3];
725 linstant->indecies[j+1] = indecies[i*3+1];
726 linstant->indecies[j+2] = indecies[i*3+2];
727 j+=3;
728 }
729 }
730
731 if (!sh_noshadowpopping.value) return;
732
733 //Add backfacing tris also to the list
734 //and render them separately to reduce popping artefacts
735 for (i=0; i<paliashdr->numtris; i++) {
736 if (linstant->triangleVis[i]) {
737 linstant->indecies[j] = indecies[i*3];//tris[i].vertindex[0];
738 linstant->indecies[j+1] = indecies[i*3+1];//tris[i].vertindex[1];
739 linstant->indecies[j+2] = indecies[i*3+2];//tris[i].vertindex[2];
740 j+=3;
741 }
742 }
743 }
744
745
746
dist(vec3_t v1,vec3_t v2)747 float dist(vec3_t v1, vec3_t v2) {
748 vec3_t diff;
749 VectorSubtract(v1,v2,diff);
750 return Length(diff);
751 }
752
CheckLightUpdate(entity_t * e,aliashdr_t * paliashdr,aliaslightinstant_t * ins,aliasframeinstant_t * aliasframeinstant)753 qboolean CheckLightUpdate(entity_t *e, aliashdr_t *paliashdr, aliaslightinstant_t *ins, aliasframeinstant_t *aliasframeinstant) {
754
755 if (sh_nocache.value) return true;
756
757 if ((ins->lastent == e) &&
758 (ins->lastlight == currentshadowlight) &&
759 (dist(ins->lastlorg,currentshadowlight->origin) < DIST_DELTA) &&
760 (dist(ins->lasteorg,e->origin) < DIST_DELTA) &&
761 (dist(ins->lasteangles,e->angles) < ANG_DELTA) &&
762 (abs(ins->lastlradius - currentshadowlight->radius) <= RADIUS_DELTA) &&
763 (ins->lastframeinstant == aliasframeinstant) &&
764 (aliasframeinstant->updateframe != r_framecount))
765 {
766 return false;
767 } else {
768 return true;
769 }
770 }
771
CheckHalfAngle(aliaslightinstant_t * ins)772 qboolean CheckHalfAngle(aliaslightinstant_t *ins)
773 {
774 if (dist(ins->lastvorg,r_refdef.vieworg) < 0.5)
775 {
776 return false;
777 } else {
778 return true;
779 }
780 }
781
782
R_SetupSurfaceInstantForLight(entity_t * e,aliashdr_t * paliashdr,aliasframeinstant_t * aliasframeinstant)783 void R_SetupSurfaceInstantForLight(entity_t *e,aliashdr_t *paliashdr, aliasframeinstant_t *aliasframeinstant)
784 {
785 aliaslightinstant_t *aliaslightinstant;
786 qboolean update;
787
788 aliaslightinstant = R_AllocateLightInstant(e, paliashdr);
789 aliasframeinstant->lightinstant = aliaslightinstant;
790
791 R_SetupObjectSpace(e, aliaslightinstant);
792
793 update = CheckLightUpdate(e,paliashdr, aliaslightinstant,aliasframeinstant);
794 if (update)
795 {
796 R_CalcVolumeVerts(aliasframeinstant, aliaslightinstant);
797
798 //if (!aliasframeinstant->shadowonly) {
799 if ( gl_cardtype == GENERIC || gl_cardtype == GEFORCE ) {//PA:
800 R_CalcAttenColors(aliasframeinstant, aliaslightinstant);
801 }
802 R_CalcIndeciesForLight(aliasframeinstant, aliaslightinstant);
803
804 //make sure that we can compare the next frame
805 VectorCopy(e->origin, aliaslightinstant->lasteorg);
806 VectorCopy(currentshadowlight->origin, aliaslightinstant->lastlorg);
807 VectorCopy(e->angles, aliaslightinstant->lasteangles);
808 aliaslightinstant->lastlradius = currentshadowlight->radius;
809 aliaslightinstant->lastlight = currentshadowlight;
810 aliaslightinstant->lastframeinstant = aliasframeinstant;
811 aliaslightinstant->lastent = e;
812 aliaslightinstant->lasthdr = paliashdr;
813 //}
814 }
815
816 aliasCacheRequests++;
817 //Half angles only change when the viewer changes his position
818 //this happens a lot so recalculate only this.
819 if ((update) || CheckHalfAngle(aliaslightinstant)) {
820 //if (!aliasframeinstant->shadowonly) {
821 R_SetupLightHAV(aliasframeinstant, aliaslightinstant);
822 //}
823 VectorCopy(r_refdef.vieworg,aliaslightinstant->lastvorg);
824
825 if(!update) aliasPartialCacheHits++;
826 } else {
827 aliasFullCacheHits++;
828 }
829
830 //lock it for this frame
831 aliaslightinstant->lockframe = r_framecount;
832 }
833
834
R_SetupInstantForLight(entity_t * e)835 void R_SetupInstantForLight(entity_t *e)
836 {
837 aliasframeinstant_t *aliasframeinstant;
838 alias3data_t *data;
839 aliashdr_t * paliashdr;
840 int i,maxnumsurf;
841
842
843 //PENTA: guard against model removed from cache
844
845 data = (alias3data_t *)Mod_Extradata (e->model);
846 maxnumsurf = data->numSurfaces;
847 aliasframeinstant = e->aliasframeinstant;
848
849 for (i=0;i<maxnumsurf;++i){
850
851 paliashdr = (aliashdr_t *)((char*)data + data->ofsSurfaces[i]);
852
853 if (!aliasframeinstant) {
854
855 Con_Printf("R_SetupInstantForLight: missing instant for %s\n",e->model->name);
856 //r_cache_thrash = true;
857 return;
858 }
859
860 if (aliasframeinstant->paliashdr != paliashdr) {
861 Con_Printf("R_SetupInstantForLight: Model was moved during frame, this is caused by not having enough heap memory.\n");
862 aliasframeinstant->paliashdr = paliashdr;
863 }
864
865
866 R_SetupSurfaceInstantForLight(e, paliashdr, aliasframeinstant);
867 aliasframeinstant = aliasframeinstant->_next;
868 }
869 }
870