1 /*
2 Copyright (C) 1997-2001 Id Software, Inc.
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 
20 //
21 // rf_light.c
22 // Dynamic lights
23 // Lightmaps
24 // Alias model lighting
25 //
26 
27 #include "rf_local.h"
28 
29 /*
30 =============================================================================
31 
32 	QUAKE II DYNAMIC LIGHTS
33 
34 =============================================================================
35 */
36 
37 // The lightmap texture data needs to be kept in
38 // main memory so texsubimage can update properly
39 static float	r_q2_blockLights[34*34*3];
40 
41 static vec3_t	r_q2_pointColor;
42 static vec3_t	r_q2_lightSpot;
43 
44 /*
45 =============
46 R_Q2BSP_MarkWorldLights
47 =============
48 */
R_Q2BSP_r_MarkWorldLights(mBspNode_t * node,refDLight_t * lt,uint32 bit)49 static void R_Q2BSP_r_MarkWorldLights (mBspNode_t *node, refDLight_t *lt, uint32 bit)
50 {
51 	mBspSurface_t	**mark, *surf;
52 	float			dist;
53 
54 loc0:
55 	if (node->c.q2_contents != -1)
56 		return;
57 	if (node->c.visFrame != ri.scn.visFrameCount)
58 		return;
59 
60 	dist = PlaneDiff (lt->origin, node->c.plane);
61 	if (dist > lt->intensity) {
62 		node = node->children[0];
63 		goto loc0;
64 	}
65 	if (dist < -lt->intensity) {
66 		node = node->children[1];
67 		goto loc0;
68 	}
69 	if (!BoundsIntersect (node->c.mins, node->c.maxs, lt->mins, lt->maxs))
70 		return;
71 
72 	// Mark the polygons
73 	if (node->q2_firstLitSurface) {
74 		mark = node->q2_firstLitSurface;
75 		do {
76 			surf = *mark++;
77 			if (!BoundsIntersect (surf->mins, surf->maxs, lt->mins, lt->maxs))
78 				continue;
79 
80 			if (surf->dLightFrame != ri.frameCount) {
81 				surf->dLightFrame = ri.frameCount;
82 				surf->dLightBits = 0;
83 			}
84 			surf->dLightBits |= bit;
85 		} while (*mark);
86 	}
87 
88 	R_Q2BSP_r_MarkWorldLights (node->children[0], lt, bit);
89 	R_Q2BSP_r_MarkWorldLights (node->children[1], lt, bit);
90 }
R_Q2BSP_MarkWorldLights(void)91 void R_Q2BSP_MarkWorldLights (void)
92 {
93 	refDLight_t	*lt;
94 	uint32		i;
95 
96 	if (gl_flashblend->intVal)
97 		return;
98 
99 	for (lt=ri.scn.dLightList, i=0 ; i<ri.scn.numDLights ; i++, lt++)
100 		R_Q2BSP_r_MarkWorldLights (ri.scn.worldModel->bspModel.nodes, lt, 1<<i);
101 }
102 
103 
104 /*
105 =============
106 R_Q2BSP_MarkBModelLights
107 =============
108 */
R_Q2BSP_r_MarkBModelLights(mBspNode_t * node,refDLight_t * lt,uint32 bit)109 static void R_Q2BSP_r_MarkBModelLights (mBspNode_t *node, refDLight_t *lt, uint32 bit)
110 {
111 	mBspSurface_t	**mark, *surf;
112 	float			dist;
113 
114 loc0:
115 	if (node->c.q2_contents != -1)
116 		return;
117 
118 	dist = PlaneDiff (lt->origin, node->c.plane);
119 	if (dist > lt->intensity) {
120 		node = node->children[0];
121 		goto loc0;
122 	}
123 	if (dist < -lt->intensity) {
124 		node = node->children[1];
125 		goto loc0;
126 	}
127 	if (!BoundsIntersect (node->c.mins, node->c.maxs, lt->mins, lt->maxs))
128 		return;
129 
130 	// Mark the polygons
131 	if (node->q2_firstLitSurface) {
132 		mark = node->q2_firstLitSurface;
133 		do {
134 			surf = *mark++;
135 			if (!BoundsIntersect (surf->mins, surf->maxs, lt->mins, lt->maxs))
136 				continue;
137 
138 			if (surf->dLightFrame != ri.frameCount) {
139 				surf->dLightFrame = ri.frameCount;
140 				surf->dLightBits = 0;
141 			}
142 			surf->dLightBits |= bit;
143 		} while (*mark);
144 	}
145 
146 	R_Q2BSP_r_MarkBModelLights (node->children[0], lt, bit);
147 	R_Q2BSP_r_MarkBModelLights (node->children[1], lt, bit);
148 }
R_Q2BSP_MarkBModelLights(refEntity_t * ent,vec3_t mins,vec3_t maxs)149 void R_Q2BSP_MarkBModelLights (refEntity_t *ent, vec3_t mins, vec3_t maxs)
150 {
151 	refDLight_t		*lt;
152 	refModel_t		*model = ent->model;
153 	mBspNode_t		*node;
154 	uint32			i;
155 
156 	if (!ri.scn.numDLights || gl_flashblend->intVal || !gl_dynamic->intVal || r_fullbright->intVal)
157 		return;
158 
159 	node = ent->model->bspModel.nodes + ent->model->q2BspModel.firstNode;
160 	for (i=0, lt=ri.scn.dLightList ; i<ri.scn.numDLights ; lt++, i++) {
161 		if (!BoundsIntersect (mins, maxs, lt->mins, lt->maxs))
162 			continue;
163 
164 		R_Q2BSP_r_MarkBModelLights (node, lt, 1<<i);
165 	}
166 }
167 
168 /*
169 =============================================================================
170 
171 	QUAKE II LIGHT SAMPLING
172 
173 =============================================================================
174 */
175 
176 /*
177 ===============
178 R_Q2BSP_RecursiveLightPoint
179 ===============
180 */
Q2BSP_RecursiveLightPoint(mBspNode_t * node,vec3_t start,vec3_t end)181 static int Q2BSP_RecursiveLightPoint (mBspNode_t *node, vec3_t start, vec3_t end)
182 {
183 	float			front, back, frac;
184 	int				i, s, t, ds, dt, r;
185 	int				side, map;
186 	cBspPlane_t		*plane;
187 	vec3_t			mid;
188 	mBspSurface_t	**mark, *surf;
189 	byte			*lightmap;
190 
191 	// Didn't hit anything
192 	if (node->c.q2_contents != -1)
193 		return -1;
194 
195 	// Calculate mid point
196 	plane = node->c.plane;
197 	if (plane->type < 3) {
198 		front = start[plane->type] - plane->dist;
199 		back = end[plane->type] - plane->dist;
200 	}
201 	else {
202 		front = DotProduct (start, plane->normal) - plane->dist;
203 		back = DotProduct (end, plane->normal) - plane->dist;
204 	}
205 
206 	side = front < 0;
207 	if ((back < 0) == side)
208 		return Q2BSP_RecursiveLightPoint (node->children[side], start, end);
209 
210 	frac = front / (front - back);
211 	mid[0] = start[0] + (end[0] - start[0]) * frac;
212 	mid[1] = start[1] + (end[1] - start[1]) * frac;
213 	mid[2] = start[2] + (end[2] - start[2]) * frac;
214 
215 	// Go down front side
216 	r = Q2BSP_RecursiveLightPoint (node->children[side], start, mid);
217 	if (r >= 0)
218 		return r;	// Hit something
219 
220 	if ((back < 0) == side)
221 		return -1;	// Didn't hit anything
222 
223 	// Check for impact on this node
224 	Vec3Copy (mid, r_q2_lightSpot);
225 
226 	if (node->q2_firstLitSurface) {
227 		mark = node->q2_firstLitSurface;
228 		do {
229 			surf = *mark++;
230 
231 			s = Q_ftol (DotProduct (mid, surf->q2_texInfo->vecs[0]) + surf->q2_texInfo->vecs[0][3]);
232 			t = Q_ftol (DotProduct (mid, surf->q2_texInfo->vecs[1]) + surf->q2_texInfo->vecs[1][3]);
233 			if (s < surf->q2_textureMins[0] || t < surf->q2_textureMins[1])
234 				continue;
235 
236 			ds = s - surf->q2_textureMins[0];
237 			dt = t - surf->q2_textureMins[1];
238 			if (ds > surf->q2_extents[0] || dt > surf->q2_extents[1])
239 				continue;
240 
241 			ds >>= 4;
242 			dt >>= 4;
243 
244 			lightmap = surf->q2_lmSamples;
245 			Vec3Clear (r_q2_pointColor);
246 			if (lightmap) {
247 				vec3_t scale;
248 
249 				lightmap += 3 * (dt*surf->q2_lmWidth + ds);
250 
251 				for (map=0 ; map<surf->q2_numStyles ; map++) {
252 					Vec3Scale (ri.scn.lightStyles[surf->q2_styles[map]].rgb, gl_modulate->floatVal, scale);
253 					for (i=0 ; i<3 ; i++)
254 						r_q2_pointColor[i] += lightmap[i] * scale[i] * (1.0f/255.0f);
255 
256 					lightmap += 3*surf->q2_lmWidth*surf->q2_lmWidth;
257 				}
258 			}
259 
260 			return 1;
261 		} while (*mark);
262 	}
263 
264 	// Go down back side
265 	return Q2BSP_RecursiveLightPoint (node->children[!side], mid, end);
266 }
R_Q2BSP_RecursiveLightPoint(vec3_t point,vec3_t end)267 static qBool R_Q2BSP_RecursiveLightPoint (vec3_t point, vec3_t end)
268 {
269 	int	r;
270 
271 	if (ri.def.rdFlags & RDF_NOWORLDMODEL || !ri.scn.worldModel->q2BspModel.lightData) {
272 		Vec3Set (r_q2_pointColor, 1, 1, 1);
273 		return qFalse;
274 	}
275 
276 	r = Q2BSP_RecursiveLightPoint (ri.scn.worldModel->bspModel.nodes, point, end);
277 
278 	if (r == -1) {
279 		Vec3Clear (r_q2_pointColor);
280 		return qFalse;
281 	}
282 
283 	return qTrue;
284 }
285 
286 
287 /*
288 ===============
289 R_Q2BSP_ShadowForEntity
290 ===============
291 */
R_Q2BSP_ShadowForEntity(refEntity_t * ent,vec3_t shadowSpot)292 static qBool R_Q2BSP_ShadowForEntity (refEntity_t *ent, vec3_t shadowSpot)
293 {
294 	vec3_t		end;
295 
296 	Vec3Set (end, ent->origin[0], ent->origin[1], ent->origin[2] - 2048);
297 
298 	if (R_Q2BSP_RecursiveLightPoint (ent->origin, end)) {
299 		// Found!
300 		Vec3Copy (r_q2_lightSpot, shadowSpot);
301 		return qTrue;
302 	}
303 
304 	// Not found!
305 	Vec3Clear (shadowSpot);
306 	return qFalse;
307 
308 }
309 
310 
311 /*
312 ===============
313 R_Q2BSP_LightForEntity
314 ===============
315 */
R_Q2BSP_LightForEntity(refEntity_t * ent,int numVerts,byte * bArray)316 static void R_Q2BSP_LightForEntity (refEntity_t *ent, int numVerts, byte *bArray)
317 {
318 	static vec3_t	tempColorsArray[RB_MAX_VERTS];
319 	float			*cArray;
320 	vec3_t			end;
321 	vec3_t			ambientLight;
322 	vec3_t			directedLight;
323 	int				r, g, b, i;
324 	vec3_t			dir, direction;
325 	float			dot;
326 
327 	if (!(ent->flags & RF_WEAPONMODEL) && (r_fullbright->intVal || ent->flags & RF_FULLBRIGHT))
328 		goto fullBright;
329 
330 	//
331 	// Get the lighting from below
332 	//
333 	Vec3Set (end, ent->origin[0], ent->origin[1], ent->origin[2] - 2048);
334 	if (!R_Q2BSP_RecursiveLightPoint (ent->origin, end)) {
335 		end[2] = ent->origin[2] + 16;
336 		if (!(ent->flags & RF_WEAPONMODEL) && !R_Q2BSP_RecursiveLightPoint (ent->origin, end)) {
337 			// Not found!
338 			Vec3Copy (r_q2_pointColor, ambientLight);
339 			Vec3Copy (r_q2_pointColor, directedLight);
340 		}
341 		else {
342 			// Found!
343 			Vec3Copy (r_q2_pointColor, directedLight);
344 			Vec3Scale (r_q2_pointColor, 0.6f, ambientLight);
345 		}
346 	}
347 	else {
348 		// Found!
349 		Vec3Copy (r_q2_pointColor, directedLight);
350 		Vec3Scale (r_q2_pointColor, 0.6f, ambientLight);
351 	}
352 
353 	// Save off light value for server to look at (BIG HACK!)
354 	if (ent->flags & RF_WEAPONMODEL) {
355 		// Pick the greatest component, which should be
356 		// the same as the mono value returned by software
357 		if (r_q2_pointColor[0] > r_q2_pointColor[1]) {
358 			if (r_q2_pointColor[0] > r_q2_pointColor[2])
359 				Cvar_VariableSetValue (r_lightlevel, 150 * r_q2_pointColor[0], qTrue);
360 			else
361 				Cvar_VariableSetValue (r_lightlevel, 150 * r_q2_pointColor[2], qTrue);
362 		}
363 		else {
364 			if (r_q2_pointColor[1] > r_q2_pointColor[2])
365 				Cvar_VariableSetValue (r_lightlevel, 150 * r_q2_pointColor[1], qTrue);
366 			else
367 				Cvar_VariableSetValue (r_lightlevel, 150 * r_q2_pointColor[2], qTrue);
368 		}
369 
370 	}
371 
372 	// Fullbright entity
373 	if (r_fullbright->intVal || ent->flags & RF_FULLBRIGHT) {
374 fullBright:
375 		for (i=0 ; i<numVerts ; i++, bArray+=4)
376 			*(int *)bArray = *(int *)ent->color;
377 		return;
378 	}
379 
380 	//
381 	// Flag effects
382 	//
383 	if (ent->flags & RF_MINLIGHT) {
384 		for (i=0 ; i<3 ; i++)
385 			if (ambientLight[i] > 0.1f)
386 				break;
387 
388 		if (i == 3) {
389 			ambientLight[0] += 0.1f;
390 			ambientLight[1] += 0.1f;
391 			ambientLight[2] += 0.1f;
392 		}
393 	}
394 
395 	if (ent->flags & RF_GLOW) {
396 		float	scale;
397 		float	min;
398 
399 		// Bonus items will pulse with time
400 		scale = 0.1f * (float)sin (ri.def.time * 7);
401 		for (i=0 ; i<3 ; i++) {
402 			min = ambientLight[i] * 0.8f;
403 			ambientLight[i] += scale;
404 			if (ambientLight[i] < min)
405 				ambientLight[i] = min;
406 		}
407 	}
408 
409 	//
410 	// Add ambient lights
411 	//
412 	Vec3Set (dir, -1, 0, 1);
413 	Matrix3_TransformVector (ent->axis, dir, direction);
414 
415 	for (i=0 ; i<numVerts; i++) {
416 		dot = DotProduct (rb.batch.normals[i], direction);
417 		if (dot <= 0)
418 			Vec3Copy (ambientLight, tempColorsArray[i]);
419 		else
420 			Vec3MA (ambientLight, dot, directedLight, tempColorsArray[i]);
421 	}
422 
423 	//
424 	// Add dynamic lights
425 	//
426 	if (gl_dynamic->intVal && ri.scn.numDLights) {
427 		refDLight_t	*lt;
428 		float		dist, add, intensity8, intensity;
429 		vec3_t		dlOrigin;
430 		uint32		num;
431 
432 		for (lt=ri.scn.dLightList, num=0 ; num<ri.scn.numDLights ; num++, lt++) {
433 			// FIXME: use BoundsIntersect for a performance boost, though this will meen storing bounds in the entity or something...
434 			if (!BoundsAndSphereIntersect (lt->mins, lt->maxs, ent->origin, ent->model->radius * ent->scale))
435 				continue;
436 
437 			// Translate
438 			Vec3Subtract (lt->origin, ent->origin, dir);
439 			dist = Vec3LengthFast (dir);
440 
441 			if (!dist || dist > lt->intensity + ent->model->radius * ent->scale)
442 				continue;
443 
444 			// Rotate
445 			Matrix3_TransformVector (ent->axis, dir, dlOrigin);
446 
447 			// Calculate intensity
448 			intensity = lt->intensity - dist;
449 			if (intensity <= 0)
450 				continue;
451 			intensity8 = lt->intensity * 8;
452 
453 			for (i=0 ; i<numVerts ; i++) {
454 				Vec3Subtract (dlOrigin, rb.batch.vertices[i], dir);
455 				add = DotProduct (rb.batch.normals[i], dir);
456 
457 				// Add some ambience
458 				Vec3MA (tempColorsArray[i], intensity * 0.4f * (1.0f/256.0f), lt->color, tempColorsArray[i]);
459 
460 				// Shade the verts
461 				if (add > 0) {
462 					dot = DotProduct (dir, dir);
463 					add *= (intensity8 / dot) * Q_RSqrtf (dot);
464 					if (add > 255.0f)
465 						add = 255.0f / add;
466 
467 					Vec3MA (tempColorsArray[i], add, lt->color, tempColorsArray[i]);
468 				}
469 			}
470 		}
471 	}
472 
473 	//
474 	// Clamp
475 	//
476 	cArray = tempColorsArray[0];
477 	for (i=0 ; i<numVerts ; i++, bArray+=4, cArray+=3) {
478 		r = Q_ftol (cArray[0] * ent->color[0]);
479 		g = Q_ftol (cArray[1] * ent->color[1]);
480 		b = Q_ftol (cArray[2] * ent->color[2]);
481 
482 		bArray[0] = clamp (r, 0, 255);
483 		bArray[1] = clamp (g, 0, 255);
484 		bArray[2] = clamp (b, 0, 255);
485 	}
486 }
487 
488 
489 /*
490 ===============
491 R_Q2BSP_LightPoint
492 ===============
493 */
R_Q2BSP_LightPoint(vec3_t point,vec3_t light)494 static void R_Q2BSP_LightPoint (vec3_t point, vec3_t light)
495 {
496 	vec3_t		end;
497 	vec3_t		dist;
498 	refDLight_t	*lt;
499 	float		add;
500 	uint32		num;
501 
502 	Vec3Set (end, point[0], point[1], point[2] - 2048);
503 	if (!R_Q2BSP_RecursiveLightPoint (point, end)) {
504 		end[2] = point[2] + 16;
505 		R_Q2BSP_RecursiveLightPoint (point, end);
506 	}
507 	Vec3Copy (r_q2_pointColor, light);
508 
509 	//
510 	// Add dynamic lights
511 	//
512 	for (lt=ri.scn.dLightList, num=0 ; num<ri.scn.numDLights ; num++, lt++) {
513 		Vec3Subtract (point, lt->origin, dist);
514 		add = (lt->intensity - Vec3Length (dist)) * (1.0f/256.0f);
515 
516 		if (add > 0)
517 			Vec3MA (light, add, lt->color, light);
518 	}
519 }
520 
521 
522 /*
523 ====================
524 R_Q2BSP_SetLightLevel
525 
526 Save off light value for server to look at (BIG HACK!)
527 ====================
528 */
R_Q2BSP_SetLightLevel(void)529 static void R_Q2BSP_SetLightLevel (void)
530 {
531 	vec3_t		shadelight;
532 
533 	R_Q2BSP_LightPoint (ri.def.viewOrigin, shadelight);
534 
535 	// Pick the greatest component, which should be
536 	// the same as the mono value returned by software
537 	if (shadelight[0] > shadelight[1]) {
538 		if (shadelight[0] > shadelight[2])
539 			Cvar_VariableSetValue (r_lightlevel, 150 * shadelight[0], qTrue);
540 		else
541 			Cvar_VariableSetValue (r_lightlevel, 150 * shadelight[2], qTrue);
542 	}
543 	else {
544 		if (shadelight[1] > shadelight[2])
545 			Cvar_VariableSetValue (r_lightlevel, 150 * shadelight[1], qTrue);
546 		else
547 			Cvar_VariableSetValue (r_lightlevel, 150 * shadelight[2], qTrue);
548 	}
549 
550 }
551 
552 /*
553 =============================================================================
554 
555 	QUAKE II LIGHTMAP
556 
557 =============================================================================
558 */
559 
560 static byte		*r_q2_lmBuffer;
561 static int		r_q2_lmNumUploaded;
562 static int		*r_q2_lmAllocated;
563 int				r_q2_lmSize;
564 
565 /*
566 ===============
567 R_Q2BSP_AddDynamicLights
568 ===============
569 */
R_Q2BSP_AddDynamicLights(mBspSurface_t * surf)570 static void R_Q2BSP_AddDynamicLights (mBspSurface_t *surf)
571 {
572 	int			sd, td, s, t;
573 	float		fDist, fDist2, fRad;
574 	float		scale, sl, st;
575 	float		fsacc, ftacc;
576 	float		*bl;
577 	vec3_t		impact;
578 	refDLight_t	*lt;
579 	uint32		num;
580 
581 	for (num=0, lt=ri.scn.dLightList ; num<ri.scn.numDLights ; num++, lt++) {
582 		if (!(surf->dLightBits & (1<<num)))
583 			continue;	// Not lit by this light
584 
585 		fDist = PlaneDiff (lt->origin, surf->q2_plane);
586 		fRad = lt->intensity - (float)fabs (fDist); // fRad is now the highest intensity on the plane
587 		if (fRad < 0)
588 			continue;
589 
590 		impact[0] = lt->origin[0] - (surf->q2_plane->normal[0] * fDist);
591 		impact[1] = lt->origin[1] - (surf->q2_plane->normal[1] * fDist);
592 		impact[2] = lt->origin[2] - (surf->q2_plane->normal[2] * fDist);
593 
594 		sl = DotProduct (impact, surf->q2_texInfo->vecs[0]) + surf->q2_texInfo->vecs[0][3] - surf->q2_textureMins[0];
595 		st = DotProduct (impact, surf->q2_texInfo->vecs[1]) + surf->q2_texInfo->vecs[1][3] - surf->q2_textureMins[1];
596 
597 		bl = r_q2_blockLights;
598 		for (t=0, ftacc=0 ; t<surf->q2_lmHeight ; t++) {
599 			td = Q_ftol (st - ftacc);
600 			if (td < 0)
601 				td = -td;
602 
603 			for (s=0, fsacc=0 ; s<surf->q2_lmWidth ; s++) {
604 				sd = Q_ftol (sl - fsacc);
605 				if (sd < 0)
606 					sd = -sd;
607 
608 				if (sd > td) {
609 					fDist = (float)(sd + (td>>1));
610 					fDist2 = (float)(sd + (td<<1));
611 				}
612 				else {
613 					fDist = (float)(td + (sd>>1));
614 					fDist2 = (float)(td + (sd<<1));
615 				}
616 
617 				if (fDist < fRad) {
618 					scale = fRad - fDist;
619 
620 					bl[0] += lt->color[0] * scale;
621 					bl[1] += lt->color[1] * scale;
622 					bl[2] += lt->color[2] * scale;
623 
624 					// Amplify the center a little
625 					if (fDist2 < fRad) {
626 						scale = fRad - fDist2;
627 						bl[0] += lt->color[0] * scale * 0.5f;
628 						bl[1] += lt->color[1] * scale * 0.5f;
629 						bl[2] += lt->color[2] * scale * 0.5f;
630 					}
631 				}
632 
633 				fsacc += 16;
634 				bl += 3;
635 			}
636 
637 			ftacc += 16;
638 		}
639 	}
640 }
641 
642 
643 /*
644 ===============
645 R_Q2BSP_BuildLightMap
646 
647 Combine and scale multiple lightmaps into the floating format in blocklights
648 ===============
649 */
R_Q2BSP_BuildLightMap(mBspSurface_t * surf,byte * dest,int stride)650 static void R_Q2BSP_BuildLightMap (mBspSurface_t *surf, byte *dest, int stride)
651 {
652 	int			i, j, size;
653 	int			map;
654 	float		*bl, max;
655 	vec3_t		scale;
656 	byte		*lightMap;
657 
658 	if (surf->q2_texInfo->flags & (SURF_TEXINFO_SKY|SURF_TEXINFO_WARP))
659 		Com_Error (ERR_DROP, "LM_BuildLightMap called for non-lit surface");
660 
661 	size = surf->q2_lmWidth*surf->q2_lmHeight;
662 	if (size > sizeof (r_q2_blockLights) >> 4)
663 		Com_Error (ERR_DROP, "Bad r_q2_blockLights size");
664 
665 	// Set to full bright if no light data
666 	if (!surf->q2_lmSamples || r_fullbright->intVal) {
667 		for (i=0 ; i<size*3 ; i++)
668 			r_q2_blockLights[i] = 255.0f;
669 	}
670 	else {
671 		lightMap = surf->q2_lmSamples;
672 
673 		// Add all the lightmaps
674 		if (surf->q2_numStyles == 1) {
675 			bl = r_q2_blockLights;
676 
677 			// Optimal case
678 			Vec3Scale (ri.scn.lightStyles[surf->q2_styles[0]].rgb, gl_modulate->floatVal, scale);
679 			if (scale[0] == 1.0f && scale[1] == 1.0f && scale[2] == 1.0f) {
680 				for (i=0 ; i<size ; i++) {
681 					bl[0] = lightMap[i*3+0];
682 					bl[1] = lightMap[i*3+1];
683 					bl[2] = lightMap[i*3+2];
684 
685 					bl += 3;
686 				}
687 			}
688 			else {
689 				for (i=0 ; i<size ; i++) {
690 					bl[0] = lightMap[i*3+0] * scale[0];
691 					bl[1] = lightMap[i*3+1] * scale[1];
692 					bl[2] = lightMap[i*3+2] * scale[2];
693 
694 					bl += 3;
695 				}
696 			}
697 
698 			// Skip to next lightmap
699 			lightMap += size*3;
700 		}
701 		else {
702 			map = 0;
703 			bl = r_q2_blockLights;
704 			Vec3Scale (ri.scn.lightStyles[surf->q2_styles[map]].rgb, gl_modulate->floatVal, scale);
705 			if (scale[0] == 1.0f && scale[1] == 1.0f && scale[2] == 1.0f) {
706 				for (i=0 ; i<size ; i++, bl+=3) {
707 					bl[0] = lightMap[i*3+0];
708 					bl[1] = lightMap[i*3+1];
709 					bl[2] = lightMap[i*3+2];
710 				}
711 			}
712 			else {
713 				for (i=0 ; i<size ; i++, bl+=3) {
714 					bl[0] = lightMap[i*3+0] * scale[0];
715 					bl[1] = lightMap[i*3+1] * scale[1];
716 					bl[2] = lightMap[i*3+2] * scale[2];
717 				}
718 			}
719 
720 			// Skip to next lightmap
721 			lightMap += size*3;
722 
723 			for (map=1 ; map<surf->q2_numStyles ; map++) {
724 				bl = r_q2_blockLights;
725 
726 				Vec3Scale (ri.scn.lightStyles[surf->q2_styles[map]].rgb, gl_modulate->floatVal, scale);
727 				if (scale[0] == 1.0f && scale[1] == 1.0f && scale[2] == 1.0f) {
728 					for (i=0 ; i<size ; i++, bl+=3) {
729 						bl[0] += lightMap[i*3+0];
730 						bl[1] += lightMap[i*3+1];
731 						bl[2] += lightMap[i*3+2];
732 					}
733 				}
734 				else {
735 					for (i=0 ; i<size ; i++, bl+=3) {
736 						bl[0] += lightMap[i*3+0] * scale[0];
737 						bl[1] += lightMap[i*3+1] * scale[1];
738 						bl[2] += lightMap[i*3+2] * scale[2];
739 					}
740 				}
741 
742 				// Skip to next lightmap
743 				lightMap += size*3;
744 			}
745 		}
746 
747 		// Add all the dynamic lights
748 		if (surf->dLightFrame == ri.frameCount)
749 			R_Q2BSP_AddDynamicLights (surf);
750 	}
751 
752 	// Put into texture format
753 	stride -= (surf->q2_lmWidth << 2);
754 	bl = r_q2_blockLights;
755 
756 	for (i=0 ; i<surf->q2_lmHeight ; i++) {
757 		for (j=0 ; j<surf->q2_lmWidth ; j++) {
758 			// Catch negative lights
759 			if (bl[0] < 0)
760 				bl[0] = 0;
761 			if (bl[1] < 0)
762 				bl[1] = 0;
763 			if (bl[2] < 0)
764 				bl[2] = 0;
765 
766 			// Determine the brightest of the three color components
767 			max = bl[0];
768 			if (bl[1] > max)
769 				max = bl[1];
770 			if (bl[2] > max)
771 				max = bl[2];
772 
773 			// Normalize the color components to the highest channel
774 			if (max > 255) {
775 				max = 255.0f / max;
776 
777 				dest[0] = (byte)(bl[0]*max);
778 				dest[1] = (byte)(bl[1]*max);
779 				dest[2] = (byte)(bl[2]*max);
780 				dest[3] = (byte)(255*max);
781 			}
782 			else {
783 				dest[0] = (byte)bl[0];
784 				dest[1] = (byte)bl[1];
785 				dest[2] = (byte)bl[2];
786 				dest[3] = 255;
787 			}
788 
789 			bl += 3;
790 			dest += 4;
791 		}
792 
793 		dest += stride;
794 	}
795 }
796 
797 
798 /*
799 ===============
800 R_Q2BSP_SetLMCacheState
801 ===============
802 */
R_Q2BSP_SetLMCacheState(mBspSurface_t * surf)803 static void R_Q2BSP_SetLMCacheState (mBspSurface_t *surf)
804 {
805 	int		map;
806 
807 	for (map=0 ; map<surf->q2_numStyles ; map++)
808 		surf->q2_cachedLight[map] = ri.scn.lightStyles[surf->q2_styles[map]].white;
809 }
810 
811 
812 /*
813 =======================
814 R_Q2BSP_UpdateLightmap
815 =======================
816 */
R_Q2BSP_UpdateLightmap(mBspSurface_t * surf)817 void R_Q2BSP_UpdateLightmap (mBspSurface_t *surf)
818 {
819 	static uint32	temp[Q2LIGHTMAP_WIDTH*Q2LIGHTMAP_WIDTH];
820 	int				map;
821 
822 	// Don't attempt a surface more than once a frame
823 	// FIXME: This is just a nasty work-around at best
824 	if (surf->q2_lmFrame == ri.frameCount)
825 		return;
826 	surf->q2_lmFrame = ri.frameCount;
827 
828 	// Is this surface allowed to have a lightmap?
829 	if (surf->q2_texInfo->flags & (SURF_TEXINFO_SKY|SURF_TEXINFO_WARP)) {
830 		surf->q2_lmTexNumActive = -1;
831 		return;
832 	}
833 
834 	// Dynamic this frame or dynamic previously
835 	if (gl_dynamic->intVal) {
836 		for (map=0 ; map<surf->q2_numStyles ; map++) {
837 			if (ri.scn.lightStyles[surf->q2_styles[map]].white != surf->q2_cachedLight[map])
838 				goto dynamic;
839 		}
840 
841 		if (surf->dLightFrame == ri.frameCount)
842 			goto dynamic;
843 	}
844 
845 	// No need to update
846 	surf->q2_lmTexNumActive = surf->lmTexNum;
847 	return;
848 
849 dynamic:
850 	// Update texture
851 	R_Q2BSP_BuildLightMap (surf, (void *)temp, surf->q2_lmWidth*4);
852 	if ((surf->q2_styles[map] >= 32 || surf->q2_styles[map] == 0) && surf->dLightFrame != ri.frameCount) {
853 		R_Q2BSP_SetLMCacheState (surf);
854 
855 		RB_BindTexture (r_lmTextures[surf->lmTexNum]);
856 		surf->q2_lmTexNumActive = surf->lmTexNum;
857 	}
858 	else {
859 		RB_BindTexture (r_lmTextures[0]);
860 		surf->q2_lmTexNumActive = 0;
861 	}
862 
863 	qglTexSubImage2D (GL_TEXTURE_2D, 0,
864 					surf->q2_lmCoords[0], surf->q2_lmCoords[1],
865 					surf->q2_lmWidth, surf->q2_lmHeight,
866 					GL_RGBA,
867 					GL_UNSIGNED_BYTE,
868 					temp);
869 }
870 
871 
872 /*
873 ================
874 R_Q2BSP_UploadLMBlock
875 ================
876 */
R_Q2BSP_UploadLMBlock(void)877 static void R_Q2BSP_UploadLMBlock (void)
878 {
879 	if (r_q2_lmNumUploaded+1 >= R_MAX_LIGHTMAPS)
880 		Com_Error (ERR_DROP, "R_Q2BSP_UploadLMBlock: - R_MAX_LIGHTMAPS exceeded\n");
881 
882 	r_lmTextures[r_q2_lmNumUploaded++] = R_Load2DImage (Q_VarArgs ("*lm%i", r_q2_lmNumUploaded), (byte **)(&r_q2_lmBuffer),
883 		r_q2_lmSize, r_q2_lmSize, IF_NOPICMIP|IF_NOMIPMAP_LINEAR|IF_NOGAMMA|IF_NOINTENS|IF_NOCOMPRESS|IT_LIGHTMAP, 3);
884 }
885 
886 
887 /*
888 ================
889 R_Q2BSP_AllocLMBlock
890 
891 Returns a texture number and the position inside it
892 ================
893 */
R_Q2BSP_AllocLMBlock(int w,int h,int * x,int * y)894 static qBool R_Q2BSP_AllocLMBlock (int w, int h, int *x, int *y)
895 {
896 	int		i, j;
897 	int		best, best2;
898 
899 	best = r_q2_lmSize;
900 	for (i=0 ; i<r_q2_lmSize-w ; i++) {
901 		best2 = 0;
902 
903 		for (j=0 ; j<w ; j++) {
904 			if (r_q2_lmAllocated[i+j] >= best)
905 				break;
906 
907 			if (r_q2_lmAllocated[i+j] > best2)
908 				best2 = r_q2_lmAllocated[i+j];
909 		}
910 
911 		if (j == w) {
912 			// This is a valid spot
913 			*x = i;
914 			*y = best = best2;
915 		}
916 	}
917 
918 	if (best + h > r_q2_lmSize)
919 		return qFalse;
920 
921 	for (i=0 ; i<w ; i++)
922 		r_q2_lmAllocated[*x + i] = best + h;
923 
924 	return qTrue;
925 }
926 
927 
928 /*
929 ==================
930 R_Q2BSP_BeginBuildingLightmaps
931 ==================
932 */
R_Q2BSP_BeginBuildingLightmaps(void)933 void R_Q2BSP_BeginBuildingLightmaps (void)
934 {
935 	int		size, i;
936 
937 	// Should be no lightmaps at this point
938 	r_q2_lmNumUploaded = 0;
939 
940 	// Find the maximum size
941 	for (size=1 ; size<Q2LIGHTMAP_WIDTH && size<ri.config.maxTexSize ; size<<=1);
942 	r_q2_lmSize = size;
943 
944 	// Allocate buffers and clear values
945 	r_q2_lmAllocated = Mem_PoolAllocExt (sizeof (int) * r_q2_lmSize, qTrue, ri.lightSysPool, 0);
946 	r_q2_lmBuffer = Mem_PoolAllocExt (r_q2_lmSize*r_q2_lmSize*4, qFalse, ri.lightSysPool, 0);
947 	memset (r_q2_lmBuffer, 255, r_q2_lmSize*r_q2_lmSize*4);
948 
949 	// Setup the base light styles
950 	for (i=0 ; i<MAX_CS_LIGHTSTYLES ; i++) {
951 		Vec3Set (ri.scn.lightStyles[i].rgb, 1, 1, 1);
952 		ri.scn.lightStyles[i].white = 3;
953 	}
954 
955 	// Initialize the base dynamic lightmap texture
956 	R_Q2BSP_UploadLMBlock ();
957 }
958 
959 
960 /*
961 ========================
962 R_Q2BSP_CreateSurfaceLightmap
963 ========================
964 */
R_Q2BSP_CreateSurfaceLightmap(mBspSurface_t * surf)965 void R_Q2BSP_CreateSurfaceLightmap (mBspSurface_t *surf)
966 {
967 	byte	*base;
968 
969 	if (!R_Q2BSP_AllocLMBlock (surf->q2_lmWidth, surf->q2_lmHeight, &surf->q2_lmCoords[0], &surf->q2_lmCoords[1])) {
970 		R_Q2BSP_UploadLMBlock ();
971 		memset (r_q2_lmAllocated, 0, sizeof (int) * r_q2_lmSize);
972 
973 		if (!R_Q2BSP_AllocLMBlock (surf->q2_lmWidth, surf->q2_lmHeight, &surf->q2_lmCoords[0], &surf->q2_lmCoords[1]))
974 			Com_Error (ERR_FATAL, "Consecutive calls to R_Q2BSP_AllocLMBlock (%d, %d) failed\n", surf->q2_lmWidth, surf->q2_lmHeight);
975 	}
976 
977 	surf->lmTexNum = r_q2_lmNumUploaded;
978 	surf->q2_lmTexNumActive = -1;
979 	surf->q2_lmFrame = ri.frameCount - 1;	// Force an update
980 
981 	base = r_q2_lmBuffer + ((surf->q2_lmCoords[1] * r_q2_lmSize + surf->q2_lmCoords[0]) * 4);
982 
983 	R_Q2BSP_SetLMCacheState (surf);
984 	R_Q2BSP_BuildLightMap (surf, base, r_q2_lmSize*4);
985 }
986 
987 
988 /*
989 =======================
990 R_Q2BSP_EndBuildingLightmaps
991 =======================
992 */
R_Q2BSP_EndBuildingLightmaps(void)993 void R_Q2BSP_EndBuildingLightmaps (void)
994 {
995 	// Upload the final block
996 	R_Q2BSP_UploadLMBlock ();
997 
998 	// Release allocated memory
999 	Mem_Free (r_q2_lmAllocated);
1000 	Mem_Free (r_q2_lmBuffer);
1001 }
1002 
1003 
1004 /*
1005 =======================
1006 R_Q2BSP_TouchLightmaps
1007 =======================
1008 */
R_Q2BSP_TouchLightmaps(void)1009 static void R_Q2BSP_TouchLightmaps (void)
1010 {
1011 	int		i;
1012 
1013 	for (i=0 ; i<r_q2_lmNumUploaded ; i++)
1014 		R_TouchImage (r_lmTextures[i]);
1015 }
1016 
1017 /*
1018 =============================================================================
1019 
1020 	QUAKE III DYNAMIC LIGHTS
1021 
1022 =============================================================================
1023 */
1024 
1025 #define Q3_DLIGHT_SCALE 0.5f
1026 
1027 /*
1028 =================
1029 R_Q3BSP_MarkLitSurfaces
1030 =================
1031 */
R_Q3BSP_MarkLitSurfaces(refDLight_t * lt,float lightIntensity,uint32 bit,mBspNode_t * node)1032 static void R_Q3BSP_MarkLitSurfaces (refDLight_t *lt, float lightIntensity, uint32 bit, mBspNode_t *node)
1033 {
1034 	mBspLeaf_t		*leaf;
1035 	mBspSurface_t	*surf, **mark;
1036 	float			dist;
1037 
1038 	for ( ; ; ) {
1039 		if (node->c.visFrame != ri.scn.visFrameCount)
1040 			return;
1041 		if (node->c.plane == NULL)
1042 			break;
1043 
1044 		dist = PlaneDiff (lt->origin, node->c.plane);
1045 		if (dist > lightIntensity) {
1046 			node = node->children[0];
1047 			continue;
1048 		}
1049 
1050 		if (dist >= -lightIntensity)
1051 			R_Q3BSP_MarkLitSurfaces (lt, lightIntensity, bit, node->children[0]);
1052 		node = node->children[1];
1053 	}
1054 
1055 	leaf = (mBspLeaf_t *)node;
1056 
1057 	// Check for door connected areas
1058 	if (ri.def.areaBits) {
1059 		if (!(ri.def.areaBits[leaf->area>>3] & (1<<(leaf->area&7))))
1060 			return;		// Not visible
1061 	}
1062 	if (!leaf->q3_firstLitSurface)
1063 		return;
1064 	if (!BoundsIntersect (leaf->c.mins, leaf->c.maxs, lt->mins, lt->maxs))
1065 		return;
1066 
1067 	mark = leaf->q3_firstLitSurface;
1068 	do {
1069 		surf = *mark++;
1070 		if (!BoundsIntersect (surf->mins, surf->maxs, lt->mins, lt->maxs))
1071 			continue;
1072 
1073 		if (surf->dLightFrame != ri.frameCount) {
1074 			surf->dLightBits = 0;
1075 			surf->dLightFrame = ri.frameCount;
1076 		}
1077 		surf->dLightBits |= bit;
1078 	} while (*mark);
1079 }
1080 
1081 
1082 /*
1083 =================
1084 R_Q3BSP_MarkWorldLights
1085 =================
1086 */
R_Q3BSP_MarkWorldLights(void)1087 void R_Q3BSP_MarkWorldLights (void)
1088 {
1089 	refDLight_t	*lt;
1090 	uint32		i;
1091 
1092 	if (gl_flashblend->intVal || !gl_dynamic->intVal || !ri.scn.numDLights || r_vertexLighting->intVal || r_fullbright->intVal)
1093 		return;
1094 
1095 	lt = ri.scn.dLightList;
1096 	for (i=0 ; i<ri.scn.numDLights ; i++, lt++)
1097 		R_Q3BSP_MarkLitSurfaces (lt, lt->intensity*Q3_DLIGHT_SCALE, 1<<i, ri.scn.worldModel->bspModel.nodes);
1098 }
1099 
1100 
1101 /*
1102 =================
1103 R_Q3BSP_MarkBModelLights
1104 =================
1105 */
R_Q3BSP_MarkBModelLights(refEntity_t * ent,vec3_t mins,vec3_t maxs)1106 void R_Q3BSP_MarkBModelLights (refEntity_t *ent, vec3_t mins, vec3_t maxs)
1107 {
1108 	refDLight_t		*lt;
1109 	refModel_t		*model = ent->model;
1110 	mBspSurface_t	*surf;
1111 	uint32			i;
1112 	int				j;
1113 
1114 	if (!gl_dynamic->intVal || !ri.scn.numDLights || r_fullbright->intVal)
1115 		return;
1116 
1117 	for (i=0, lt=ri.scn.dLightList ; i<ri.scn.numDLights ; i++, lt++) {
1118 		if (!BoundsIntersect (mins, maxs, lt->mins, lt->maxs))
1119 			continue;
1120 
1121 		for (j=0, surf=model->bspModel.firstModelSurface ; j<model->bspModel.numModelSurfaces ; j++, surf++) {
1122 			if (R_Q3BSP_SurfPotentiallyLit (surf)) {
1123 				if (surf->dLightFrame != ri.frameCount) {
1124 					surf->dLightBits = 0;
1125 					surf->dLightFrame = ri.frameCount;
1126 				}
1127 				surf->dLightBits |= 1<<i;
1128 			}
1129 		}
1130 	}
1131 }
1132 
1133 /*
1134 =============================================================================
1135 
1136 	QUAKE III LIGHT SAMPLING
1137 
1138 =============================================================================
1139 */
1140 
1141 /*
1142 ===============
1143 R_Q3BSP_LightForEntity
1144 ===============
1145 */
R_Q3BSP_LightForEntity(refEntity_t * ent,int numVerts,byte * bArray)1146 static void R_Q3BSP_LightForEntity (refEntity_t *ent, int numVerts, byte *bArray)
1147 {
1148 	static vec3_t	tempColorsArray[RB_MAX_VERTS];
1149 	vec3_t			vf, vf2;
1150 	float			*cArray;
1151 	float			t[8], direction_uv[2], dot;
1152 	int				r, g, b, vi[3], i, j, index[4];
1153 	vec3_t			dlorigin, ambient, diffuse, dir, direction;
1154 	float			*gridSize, *gridMins;
1155 	int				*gridBounds;
1156 
1157 	// Fullbright entity
1158 	if (r_fullbright->intVal || ent->flags & RF_FULLBRIGHT) {
1159 		for (i=0 ; i<numVerts ; i++, bArray+=4)
1160 			*(int *)bArray = *(int *)ent->color;
1161 		return;
1162 	}
1163 
1164 	// Probably a weird shader, see mpteam4 for example
1165 	if (!ent->model || ent->model->type == MODEL_Q3BSP) {
1166 		memset (bArray, 0, sizeof (bvec4_t)*numVerts);
1167 		return;
1168 	}
1169 
1170 	Vec3Set (ambient, 0, 0, 0);
1171 	Vec3Set (diffuse, 0, 0, 0);
1172 	Vec3Set (direction, 1, 1, 1);
1173 
1174 	gridSize = ri.scn.worldModel->q3BspModel.gridSize;
1175 	gridMins = ri.scn.worldModel->q3BspModel.gridMins;
1176 	gridBounds = ri.scn.worldModel->q3BspModel.gridBounds;
1177 
1178 	if (!ri.scn.worldModel->q3BspModel.lightGrid || !ri.scn.worldModel->q3BspModel.numLightGridElems)
1179 		goto dynamic;
1180 
1181 	for (i=0 ; i<3 ; i++) {
1182 		vf[i] = (ent->origin[i] - ri.scn.worldModel->q3BspModel.gridMins[i]) / ri.scn.worldModel->q3BspModel.gridSize[i];
1183 		vi[i] = (int)vf[i];
1184 		vf[i] = vf[i] - floor(vf[i]);
1185 		vf2[i] = 1.0f - vf[i];
1186 	}
1187 
1188 	index[0] = vi[2]*ri.scn.worldModel->q3BspModel.gridBounds[3] + vi[1]*ri.scn.worldModel->q3BspModel.gridBounds[0] + vi[0];
1189 	index[1] = index[0] + ri.scn.worldModel->q3BspModel.gridBounds[0];
1190 	index[2] = index[0] + ri.scn.worldModel->q3BspModel.gridBounds[3];
1191 	index[3] = index[2] + ri.scn.worldModel->q3BspModel.gridBounds[0];
1192 	for (i=0 ; i<4 ; i++) {
1193 		if (index[i] < 0 || index[i] >= ri.scn.worldModel->q3BspModel.numLightGridElems-1)
1194 			goto dynamic;
1195 	}
1196 
1197 	t[0] = vf2[0] * vf2[1] * vf2[2];
1198 	t[1] = vf[0] * vf2[1] * vf2[2];
1199 	t[2] = vf2[0] * vf[1] * vf2[2];
1200 	t[3] = vf[0] * vf[1] * vf2[2];
1201 	t[4] = vf2[0] * vf2[1] * vf[2];
1202 	t[5] = vf[0] * vf2[1] * vf[2];
1203 	t[6] = vf2[0] * vf[1] * vf[2];
1204 	t[7] = vf[0] * vf[1] * vf[2];
1205 
1206 	for (j=0 ; j<3 ; j++) {
1207 		ambient[j] = 0;
1208 		diffuse[j] = 0;
1209 
1210 		for (i=0 ; i<4 ; i++) {
1211 			ambient[j] += t[i*2] * ri.scn.worldModel->q3BspModel.lightGrid[index[i]].ambient[j];
1212 			ambient[j] += t[i*2+1] * ri.scn.worldModel->q3BspModel.lightGrid[index[i]+1].ambient[j];
1213 
1214 			diffuse[j] += t[i*2] * ri.scn.worldModel->q3BspModel.lightGrid[index[i]].diffuse[j];
1215 			diffuse[j] += t[i*2+1] * ri.scn.worldModel->q3BspModel.lightGrid[index[i]+1].diffuse[j];
1216 		}
1217 	}
1218 
1219 	for (j=0 ; j<2 ; j++) {
1220 		direction_uv[j] = 0;
1221 
1222 		for (i=0 ; i<4 ; i++) {
1223 			direction_uv[j] += t[i*2] * ri.scn.worldModel->q3BspModel.lightGrid[index[i]].direction[j];
1224 			direction_uv[j] += t[i*2+1] * ri.scn.worldModel->q3BspModel.lightGrid[index[i]+1].direction[j];
1225 		}
1226 
1227 		direction_uv[j] = AngleModf (direction_uv[j]);
1228 	}
1229 
1230 	dot = bound(0.0f, /*r_ambientscale->floatVal*/ 1.0f, 1.0f) * ri.pow2MapOvrbr;
1231 	Vec3Scale (ambient, dot, ambient);
1232 
1233 	dot = bound(0.0f, /*r_directedscale->floatVal*/ 1.0f, 1.0f) * ri.pow2MapOvrbr;
1234 	Vec3Scale (diffuse, dot, diffuse);
1235 
1236 	if (ent->flags & RF_MINLIGHT) {
1237 		for (i=0 ; i<3 ; i++)
1238 			if (ambient[i] > 0.1)
1239 				break;
1240 
1241 		if (i == 3) {
1242 			ambient[0] = 0.1f;
1243 			ambient[1] = 0.1f;
1244 			ambient[2] = 0.1f;
1245 		}
1246 	}
1247 
1248 	dot = direction_uv[0] * (1.0 / 255.0);
1249 	t[0] = RB_FastSin (dot + 0.25f);
1250 	t[1] = RB_FastSin (dot);
1251 
1252 	dot = direction_uv[1] * (1.0 / 255.0);
1253 	t[2] = RB_FastSin (dot + 0.25f);
1254 	t[3] = RB_FastSin (dot);
1255 
1256 	Vec3Set (dir, t[2] * t[1], t[3] * t[1], t[0]);
1257 
1258 	// Rotate direction
1259 	Matrix3_TransformVector (ent->axis, dir, direction);
1260 
1261 	cArray = tempColorsArray[0];
1262 	for (i=0 ; i<numVerts ; i++, cArray+=3) {
1263 		dot = DotProduct (rb.batch.normals[i], direction);
1264 
1265 		if (dot <= 0)
1266 			Vec3Copy (ambient, cArray);
1267 		else
1268 			Vec3MA (ambient, dot, diffuse, cArray);
1269 	}
1270 
1271 dynamic:
1272 	//
1273 	// Add dynamic lights
1274 	//
1275 	if (gl_dynamic->intVal && ri.scn.numDLights) {
1276 		refDLight_t	*dl;
1277 		float		dist, add, intensity8;
1278 		uint32		num;
1279 
1280 		for (num=0, dl=ri.scn.dLightList ; num<ri.scn.numDLights ; dl++, num++) {
1281 			// FIXME: use BoundsIntersect for a performance boost, though this will meen storing bounds in the entity or something...
1282 			if (!BoundsAndSphereIntersect (dl->mins, dl->maxs, ent->origin, ent->model->radius * ent->scale))
1283 				continue;
1284 
1285 			// Translate
1286 			Vec3Subtract ( dl->origin, ent->origin, dir );
1287 			dist = Vec3Length ( dir );
1288 
1289 			if (dist > dl->intensity + ent->model->radius * ent->scale)
1290 				continue;
1291 
1292 			// Rotate
1293 			Matrix3_TransformVector ( ent->axis, dir, dlorigin );
1294 
1295 			intensity8 = dl->intensity * 8;
1296 
1297 			cArray = tempColorsArray[0];
1298 			for (i=0 ; i<numVerts ; i++, cArray+=3) {
1299 				Vec3Subtract (dlorigin, rb.batch.vertices[i], dir);
1300 				add = DotProduct (rb.batch.normals[i], dir);
1301 
1302 				if (add > 0) {
1303 					dot = DotProduct (dir, dir);
1304 					add *= (intensity8 / dot) * Q_RSqrtf (dot);
1305 					Vec3MA (cArray, add, dl->color, cArray);
1306 				}
1307 			}
1308 		}
1309 	}
1310 
1311 	cArray = tempColorsArray[0];
1312 	for (i=0 ; i<numVerts ; i++, bArray+=4, cArray+=3) {
1313 		r = Q_ftol (cArray[0] * ent->color[0]);
1314 		g = Q_ftol (cArray[1] * ent->color[1]);
1315 		b = Q_ftol (cArray[2] * ent->color[2]);
1316 
1317 		bArray[0] = clamp (r, 0, 255);
1318 		bArray[1] = clamp (g, 0, 255);
1319 		bArray[2] = clamp (b, 0, 255);
1320 	}
1321 }
1322 
1323 /*
1324 =============================================================================
1325 
1326 	QUAKE III LIGHTMAP
1327 
1328 =============================================================================
1329 */
1330 
1331 static byte		*r_q3_lmBuffer;
1332 static int		r_q3_lmBufferSize;
1333 static int		r_q3_lmNumUploaded;
1334 static int		r_q3_lmMaxBlockSize;
1335 
1336 /*
1337 =======================
1338 R_Q3BSP_BuildLightmap
1339 =======================
1340 */
R_Q3BSP_BuildLightmap(int w,int h,const byte * data,byte * dest,int blockWidth)1341 static void R_Q3BSP_BuildLightmap (int w, int h, const byte *data, byte *dest, int blockWidth)
1342 {
1343 	int		x, y;
1344 	float	scale;
1345 	byte	*rgba;
1346 	float	scaled[3];
1347 
1348 	if (!data || r_fullbright->intVal) {
1349 		for (y=0 ; y<h ; y++, dest)
1350 			memset (dest + y * blockWidth, 255, w * 4);
1351 		return;
1352 	}
1353 
1354 	scale = ri.pow2MapOvrbr;
1355 	for (y=0 ; y<h ; y++) {
1356 		for (x=0, rgba=dest+y*blockWidth ; x<w ; x++, rgba+=4) {
1357 			scaled[0] = data[(y*w+x) * Q3LIGHTMAP_BYTES+0] * scale;
1358 			scaled[1] = data[(y*w+x) * Q3LIGHTMAP_BYTES+1] * scale;
1359 			scaled[2] = data[(y*w+x) * Q3LIGHTMAP_BYTES+2] * scale;
1360 
1361 			ColorNormalizeb (scaled, rgba);
1362 		}
1363 	}
1364 }
1365 
1366 
1367 /*
1368 =======================
1369 R_Q3BSP_PackLightmaps
1370 =======================
1371 */
R_Q3BSP_PackLightmaps(int num,int w,int h,int size,const byte * data,mQ3BspLightmapRect_t * rects)1372 static int R_Q3BSP_PackLightmaps (int num, int w, int h, int size, const byte *data, mQ3BspLightmapRect_t *rects)
1373 {
1374 	int i, x, y, root;
1375 	byte *block;
1376 	image_t *image;
1377 	int	rectX, rectY, rectSize;
1378 	int maxX, maxY, max, xStride;
1379 	double tw, th, tx, ty;
1380 
1381 	maxX = r_q3_lmMaxBlockSize / w;
1382 	maxY = r_q3_lmMaxBlockSize / h;
1383 	max = maxY;
1384 	if (maxY > maxX)
1385 		max = maxX;
1386 
1387 	if (r_q3_lmNumUploaded >= R_MAX_LIGHTMAPS-1)
1388 		Com_Error (ERR_DROP, "R_Q3BSP_PackLightmaps: - R_MAX_LIGHTMAPS exceeded\n");
1389 
1390 	Com_DevPrintf (0, "Packing %i lightmap(s) -> ", num);
1391 
1392 	if (!max || num == 1 || !r_lmPacking->intVal) {
1393 		// Process as it is
1394 		R_Q3BSP_BuildLightmap (w, h, data, r_q3_lmBuffer, w * 4);
1395 
1396 		image = R_Load2DImage (Q_VarArgs ("*lm%i", r_q3_lmNumUploaded), (byte **)(&r_q3_lmBuffer),
1397 			w, h, IF_CLAMP|IF_NOPICMIP|IF_NOMIPMAP_LINEAR|IF_NOGAMMA|IF_NOINTENS|IF_NOCOMPRESS|IT_LIGHTMAP, Q3LIGHTMAP_BYTES);
1398 
1399 		r_lmTextures[r_q3_lmNumUploaded] = image;
1400 		rects[0].texNum = r_q3_lmNumUploaded;
1401 
1402 		rects[0].w = 1; rects[0].x = 0;
1403 		rects[0].h = 1; rects[0].y = 0;
1404 
1405 		Com_DevPrintf (0, "%ix%i\n", 1, 1);
1406 
1407 		r_q3_lmNumUploaded++;
1408 		return 1;
1409 	}
1410 
1411 	// Find the nearest square block size
1412 	root = (int)sqrt (num);
1413 	if (root > max)
1414 		root = max;
1415 
1416 	// Keep row size a power of two
1417 	for (i=1 ; i<root ; i <<= 1);
1418 	if (i > root)
1419 		i >>= 1;
1420 	root = i;
1421 
1422 	num -= root * root;
1423 	rectX = rectY = root;
1424 
1425 	if (maxY > maxX) {
1426 		for ( ; num>=root && rectY<maxY ; rectY++, num-=root);
1427 
1428 		// Sample down if not a power of two
1429 		for (y=1 ; y<rectY ; y <<= 1);
1430 		if (y > rectY)
1431 			y >>= 1;
1432 		rectY = y;
1433 	}
1434 	else {
1435 		for ( ; num>=root && rectX<maxX ; rectX++, num-=root);
1436 
1437 		// Sample down if not a power of two
1438 		for (x=1 ; x<rectX ; x<<=1);
1439 		if (x > rectX)
1440 			x >>= 1;
1441 		rectX = x;
1442 	}
1443 
1444 	tw = 1.0 / (double)rectX;
1445 	th = 1.0 / (double)rectY;
1446 
1447 	xStride = w * 4;
1448 	rectSize = (rectX * w) * (rectY * h) * 4;
1449 	if (rectSize > r_q3_lmBufferSize) {
1450 		if (r_q3_lmBuffer)
1451 			Mem_Free (r_q3_lmBuffer);
1452 		r_q3_lmBuffer = Mem_PoolAllocExt (rectSize, qFalse, ri.lightSysPool, 0);
1453 		memset (r_q3_lmBuffer, 255, rectSize);
1454 		r_q3_lmBufferSize = rectSize;
1455 	}
1456 
1457 	block = r_q3_lmBuffer;
1458 	for (y=0, ty=0.0f, num=0 ; y<rectY ; y++, ty+=th, block+=rectX*xStride*h) {
1459 		for (x=0, tx=0.0f ; x<rectX ; x++, tx+=tw, num++) {
1460 			R_Q3BSP_BuildLightmap (w, h, data + num * size, block + x * xStride, rectX * xStride);
1461 
1462 			rects[num].w = tw; rects[num].x = tx;
1463 			rects[num].h = th; rects[num].y = ty;
1464 		}
1465 	}
1466 
1467 	image = R_Load2DImage (Q_VarArgs ("*lm%i", r_q3_lmNumUploaded), (byte **)(&r_q3_lmBuffer),
1468 		rectX * w, rectY * h, IF_CLAMP|IF_NOPICMIP|IF_NOMIPMAP_LINEAR|IF_NOGAMMA|IF_NOINTENS|IF_NOCOMPRESS|IT_LIGHTMAP, Q3LIGHTMAP_BYTES);
1469 
1470 	r_lmTextures[r_q3_lmNumUploaded] = image;
1471 	for (i=0 ; i<num ; i++)
1472 		rects[i].texNum = r_q3_lmNumUploaded;
1473 
1474 	Com_DevPrintf (0, "%ix%i\n", rectX, rectY);
1475 
1476 	r_q3_lmNumUploaded++;
1477 	return num;
1478 }
1479 
1480 
1481 /*
1482 =======================
1483 R_Q3BSP_BuildLightmaps
1484 =======================
1485 */
R_Q3BSP_BuildLightmaps(int numLightmaps,int w,int h,const byte * data,mQ3BspLightmapRect_t * rects)1486 void R_Q3BSP_BuildLightmaps (int numLightmaps, int w, int h, const byte *data, mQ3BspLightmapRect_t *rects)
1487 {
1488 	int		i;
1489 	int		size;
1490 
1491 	// Pack lightmaps
1492 	for (size=1 ; size<r_lmMaxBlockSize->intVal && size<ri.config.maxTexSize ; size<<=1);
1493 
1494 	r_q3_lmNumUploaded = 0;
1495 	r_q3_lmMaxBlockSize = size;
1496 	size = w * h * Q3LIGHTMAP_BYTES;
1497 	r_q3_lmBufferSize = w * h * 4;
1498 	r_q3_lmBuffer = Mem_PoolAllocExt (r_q3_lmBufferSize, qFalse, ri.lightSysPool, 0);
1499 
1500 	for (i=0 ; i<numLightmaps ; )
1501 		i += R_Q3BSP_PackLightmaps (numLightmaps - i, w, h, size, data + i * size, &rects[i]);
1502 
1503 	if (r_q3_lmBuffer)
1504 		Mem_Free (r_q3_lmBuffer);
1505 
1506 	Com_DevPrintf (0, "Packed %i lightmaps into %i texture(s)\n", numLightmaps, r_q3_lmNumUploaded);
1507 }
1508 
1509 
1510 /*
1511 =======================
1512 R_Q3BSP_TouchLightmaps
1513 =======================
1514 */
R_Q3BSP_TouchLightmaps(void)1515 static void R_Q3BSP_TouchLightmaps (void)
1516 {
1517 	int		i;
1518 
1519 	for (i=0 ; i<r_q3_lmNumUploaded ; i++)
1520 		R_TouchImage (r_lmTextures[i]);
1521 }
1522 
1523 /*
1524 =============================================================================
1525 
1526 	FUNCTION WRAPPING
1527 
1528 =============================================================================
1529 */
1530 
1531 /*
1532 =============
1533 R_LightBounds
1534 =============
1535 */
R_LightBounds(const vec3_t origin,float intensity,vec3_t mins,vec3_t maxs)1536 void R_LightBounds (const vec3_t origin, float intensity, vec3_t mins, vec3_t maxs)
1537 {
1538 	if (ri.scn.worldModel->type == MODEL_Q2BSP) {
1539 		Vec3Set (mins, origin[0] - (intensity * 2), origin[1] - (intensity * 2), origin[2] - (intensity * 2));
1540 		Vec3Set (maxs, origin[0] + (intensity * 2), origin[1] + (intensity * 2), origin[2] + (intensity * 2));
1541 		return;
1542 	}
1543 
1544 	Vec3Set (mins, origin[0] - intensity, origin[1] - intensity, origin[2] - intensity);
1545 	Vec3Set (maxs, origin[0] + intensity, origin[1] + intensity, origin[2] + intensity);
1546 }
1547 
1548 
1549 /*
1550 =============
1551 R_LightPoint
1552 =============
1553 */
R_LightPoint(vec3_t point,vec3_t light)1554 void R_LightPoint (vec3_t point, vec3_t light)
1555 {
1556 	if (ri.def.rdFlags & RDF_NOWORLDMODEL)
1557 		return;
1558 
1559 	if (ri.scn.worldModel->type == MODEL_Q2BSP) {
1560 		R_Q2BSP_LightPoint (point, light);
1561 		return;
1562 	}
1563 
1564 	// FIXME
1565 	Vec3Set (light, 1, 1, 1);
1566 }
1567 
1568 
1569 /*
1570 =============
1571 R_SetLightLevel
1572 =============
1573 */
R_SetLightLevel(void)1574 void R_SetLightLevel (void)
1575 {
1576 	if (ri.def.rdFlags & RDF_NOWORLDMODEL)
1577 		return;
1578 
1579 	if (ri.scn.worldModel->type == MODEL_Q2BSP) {
1580 		R_Q2BSP_SetLightLevel ();
1581 		return;
1582 	}
1583 }
1584 
1585 
1586 /*
1587 =======================
1588 R_TouchLightmaps
1589 =======================
1590 */
R_TouchLightmaps(void)1591 void R_TouchLightmaps (void)
1592 {
1593 	if (ri.def.rdFlags & RDF_NOWORLDMODEL)
1594 		return;
1595 
1596 	if (ri.scn.worldModel->type == MODEL_Q2BSP) {
1597 		R_Q2BSP_TouchLightmaps ();
1598 		return;
1599 	}
1600 
1601 	R_Q3BSP_TouchLightmaps ();
1602 }
1603 
1604 
1605 /*
1606 =============
1607 R_ShadowForEntity
1608 =============
1609 */
R_ShadowForEntity(refEntity_t * ent,vec3_t shadowSpot)1610 qBool R_ShadowForEntity (refEntity_t *ent, vec3_t shadowSpot)
1611 {
1612 	if (ri.def.rdFlags & RDF_NOWORLDMODEL)
1613 		return qFalse;
1614 
1615 	if (ri.scn.worldModel->type == MODEL_Q2BSP)
1616 		return R_Q2BSP_ShadowForEntity (ent, shadowSpot);
1617 
1618 	return qFalse;
1619 }
1620 
1621 
1622 /*
1623 =============
1624 R_LightForEntity
1625 =============
1626 */
R_LightForEntity(refEntity_t * ent,int numVerts,byte * bArray)1627 void R_LightForEntity (refEntity_t *ent, int numVerts, byte *bArray)
1628 {
1629 	if (ri.def.rdFlags & RDF_NOWORLDMODEL || ri.scn.worldModel->type == MODEL_Q2BSP) {
1630 		R_Q2BSP_LightForEntity (ent, numVerts, bArray);
1631 		return;
1632 	}
1633 
1634 	R_Q3BSP_LightForEntity (ent, numVerts, bArray);
1635 }
1636