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