1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4 
5 This file is part of GtkRadiant.
6 
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21 // qrad.c
22 
23 #include "qrad.h"
24 
25 
26 
27 /*
28 
29 NOTES
30 -----
31 
32 every surface must be divided into at least two patches each axis
33 
34 */
35 
36 patch_t		*face_patches[MAX_MAP_FACES];
37 entity_t	*face_entity[MAX_MAP_FACES];
38 patch_t		patches[MAX_PATCHES];
39 unsigned	num_patches;
40 
41 vec3_t		radiosity[MAX_PATCHES];		// light leaving a patch
42 vec3_t		illumination[MAX_PATCHES];	// light arriving at a patch
43 
44 vec3_t		face_offset[MAX_MAP_FACES];		// for rotating bmodels
45 dplane_t	backplanes[MAX_MAP_PLANES];
46 
47 extern char		inbase[32], outbase[32];
48 
49 int			fakeplanes;					// created planes for origin offset
50 
51 int		numbounce = 8;
52 qboolean	extrasamples;
53 
54 float	subdiv = 64;
55 qboolean	dumppatches;
56 
57 void BuildLightmaps (void);
58 int TestLine (vec3_t start, vec3_t stop);
59 
60 int		junk;
61 
62 float	ambient = 0;
63 float	maxlight = 196;
64 
65 float	lightscale = 1.0;
66 
67 extern qboolean	glview;
68 
69 qboolean	nopvs;
70 
71 extern char		source[1024];
72 
73 void (*CalcTextureReflectivity) (void);
74 
75 float	direct_scale =	0.4;
76 float	entity_scale =	1.0;
77 
78 /*
79 ===================================================================
80 
81 MISC
82 
83 ===================================================================
84 */
85 
86 
87 /*
88 =============
89 MakeBackplanes
90 =============
91 */
MakeBackplanes(void)92 void MakeBackplanes (void)
93 {
94 	int		i;
95 
96 	for (i=0 ; i<numplanes ; i++)
97 	{
98 		backplanes[i].dist = -dplanes[i].dist;
99 		VectorSubtract (vec3_origin, dplanes[i].normal, backplanes[i].normal);
100 	}
101 }
102 
103 int		leafparents[MAX_MAP_LEAFS];
104 int		nodeparents[MAX_MAP_NODES];
105 
106 /*
107 =============
108 MakeParents
109 =============
110 */
MakeParents(int nodenum,int parent)111 void MakeParents (int nodenum, int parent)
112 {
113 	int		i, j;
114 	dnode_t	*node;
115 
116 	nodeparents[nodenum] = parent;
117 	node = &dnodes[nodenum];
118 
119 	for (i=0 ; i<2 ; i++)
120 	{
121 		j = node->children[i];
122 		if (j < 0)
123 			leafparents[-j - 1] = nodenum;
124 		else
125 			MakeParents (j, nodenum);
126 	}
127 }
128 
129 
130 /*
131 ===================================================================
132 
133 TRANSFER SCALES
134 
135 ===================================================================
136 */
137 
PointInLeafnum(vec3_t point)138 int	PointInLeafnum (vec3_t point)
139 {
140 	int		nodenum;
141 	vec_t	dist;
142 	dnode_t	*node;
143 	dplane_t	*plane;
144 
145 	nodenum = 0;
146 	while (nodenum >= 0)
147 	{
148 		node = &dnodes[nodenum];
149 		plane = &dplanes[node->planenum];
150 		dist = DotProduct (point, plane->normal) - plane->dist;
151 		if (dist > 0)
152 			nodenum = node->children[0];
153 		else
154 			nodenum = node->children[1];
155 	}
156 
157 	return -nodenum - 1;
158 }
159 
160 
Rad_PointInLeaf(vec3_t point)161 dleaf_t		*Rad_PointInLeaf (vec3_t point)
162 {
163 	int		num;
164 
165 	num = PointInLeafnum (point);
166 	return &dleafs[num];
167 }
168 
169 
PvsForOrigin(vec3_t org,byte * pvs)170 qboolean PvsForOrigin (vec3_t org, byte *pvs)
171 {
172 	dleaf_t	*leaf;
173 
174 	if (!visdatasize)
175 	{
176 		memset (pvs, 255, (numleafs+7)/8 );
177 		return true;
178 	}
179 
180 	leaf = Rad_PointInLeaf (org);
181 	if (leaf->cluster == -1)
182 		return false;		// in solid leaf
183 
184 	DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs);
185 	return true;
186 }
187 
188 
189 /*
190 =============
191 MakeTransfers
192 
193 =============
194 */
195 int	total_transfer;
196 
MakeTransfers(int i)197 void MakeTransfers (int i)
198 {
199 	int			j;
200 	vec3_t		delta;
201 	vec_t		dist, scale;
202 	float		trans;
203 	int			itrans;
204 	patch_t		*patch, *patch2;
205 	float		total;
206 	dplane_t	plane;
207 	vec3_t		origin;
208 	float		transfers[MAX_PATCHES], *all_transfers;
209 	int			s;
210 	int			itotal;
211 	byte		pvs[(MAX_MAP_LEAFS+7)/8];
212 	int			cluster;
213 
214 	patch = patches + i;
215 	total = 0;
216 
217 	VectorCopy (patch->origin, origin);
218 	plane = *patch->plane;
219 
220 	if (!PvsForOrigin (patch->origin, pvs))
221 		return;
222 
223 	// find out which patch2s will collect light
224 	// from patch
225 
226 	all_transfers = transfers;
227 	patch->numtransfers = 0;
228 	for (j=0, patch2 = patches ; j<num_patches ; j++, patch2++)
229 	{
230 		transfers[j] = 0;
231 
232 		if (j == i)
233 			continue;
234 
235 		// check pvs bit
236 		if (!nopvs)
237 		{
238 			cluster = patch2->cluster;
239 			if (cluster == -1)
240 				continue;
241 			if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) )
242 				continue;		// not in pvs
243 		}
244 
245 		// calculate vector
246 		VectorSubtract (patch2->origin, origin, delta);
247 		dist = VectorNormalize (delta, delta);
248 		if (!dist)
249 			continue;	// should never happen
250 
251 		// reletive angles
252 		scale = DotProduct (delta, plane.normal);
253 		scale *= -DotProduct (delta, patch2->plane->normal);
254 		if (scale <= 0)
255 			continue;
256 
257 		// check exact tramsfer
258 		if (TestLine_r (0, patch->origin, patch2->origin) )
259 			continue;
260 
261 		trans = scale * patch2->area / (dist*dist);
262 
263 		if (trans < 0)
264 			trans = 0;		// rounding errors...
265 
266 		transfers[j] = trans;
267 		if (trans > 0)
268 		{
269 			total += trans;
270 			patch->numtransfers++;
271 		}
272 	}
273 
274 	// copy the transfers out and normalize
275 	// total should be somewhere near PI if everything went right
276 	// because partial occlusion isn't accounted for, and nearby
277 	// patches have underestimated form factors, it will usually
278 	// be higher than PI
279 	if (patch->numtransfers)
280 	{
281 		transfer_t	*t;
282 
283 		if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES)
284 			Error ("Weird numtransfers");
285 		s = patch->numtransfers * sizeof(transfer_t);
286 		patch->transfers = malloc (s);
287 		if (!patch->transfers)
288 			Error ("Memory allocation failure");
289 
290 		//
291 		// normalize all transfers so all of the light
292 		// is transfered to the surroundings
293 		//
294 		t = patch->transfers;
295 		itotal = 0;
296 		for (j=0 ; j<num_patches ; j++)
297 		{
298 			if (transfers[j] <= 0)
299 				continue;
300 			itrans = transfers[j]*0x10000 / total;
301 			itotal += itrans;
302 			t->transfer = itrans;
303 			t->patch = j;
304 			t++;
305 		}
306 	}
307 
308 	// don't bother locking around this.  not that important.
309 	total_transfer += patch->numtransfers;
310 }
311 
312 
313 /*
314 =============
315 FreeTransfers
316 =============
317 */
FreeTransfers(void)318 void FreeTransfers (void)
319 {
320 	int		i;
321 
322 	for (i=0 ; i<num_patches ; i++)
323 	{
324 		free (patches[i].transfers);
325 		patches[i].transfers = NULL;
326 	}
327 }
328 
329 
330 //===================================================================
331 
332 /*
333 =============
334 WriteWorld
335 =============
336 */
WriteWorld(char * name)337 void WriteWorld (char *name)
338 {
339 	int		i, j;
340 	FILE		*out;
341 	patch_t		*patch;
342 	winding_t	*w;
343 
344 	out = fopen (name, "w");
345 	if (!out)
346 		Error ("Couldn't open %s", name);
347 
348 	for (j=0, patch=patches ; j<num_patches ; j++, patch++)
349 	{
350 		w = patch->winding;
351 		fprintf (out, "%i\n", w->numpoints);
352 		for (i=0 ; i<w->numpoints ; i++)
353 		{
354 			fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
355 				w->p[i][0],
356 				w->p[i][1],
357 				w->p[i][2],
358 				patch->totallight[0],
359 				patch->totallight[1],
360 				patch->totallight[2]);
361 		}
362 		fprintf (out, "\n");
363 	}
364 
365 	fclose (out);
366 }
367 
368 /*
369 =============
370 WriteGlView
371 =============
372 */
WriteGlView(void)373 void WriteGlView (void)
374 {
375 	char	name[1024];
376 	FILE	*f;
377 	int		i, j;
378 	patch_t	*p;
379 	winding_t	*w;
380 
381 	strcpy (name, source);
382 	StripExtension (name);
383 	strcat (name, ".glr");
384 
385 	f = fopen (name, "w");
386 	if (!f)
387 		Error ("Couldn't open %s", f);
388 
389 	for (j=0 ; j<num_patches ; j++)
390 	{
391 		p = &patches[j];
392 		w = p->winding;
393 		fprintf (f, "%i\n", w->numpoints);
394 		for (i=0 ; i<w->numpoints ; i++)
395 		{
396 			fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
397 				w->p[i][0],
398 				w->p[i][1],
399 				w->p[i][2],
400 				p->totallight[0]/128,
401 				p->totallight[1]/128,
402 				p->totallight[2]/128);
403 		}
404 		fprintf (f, "\n");
405 	}
406 
407 	fclose (f);
408 }
409 
410 
411 //==============================================================
412 
413 /*
414 =============
415 CollectLight
416 =============
417 */
CollectLight(void)418 float CollectLight (void)
419 {
420 	int		i, j;
421 	patch_t	*patch;
422 	vec_t	total;
423 
424 	total = 0;
425 
426 	for (i=0, patch=patches ; i<num_patches ; i++, patch++)
427 	{
428 		// skys never collect light, it is just dropped
429 		if (patch->sky)
430 		{
431 			VectorClear (radiosity[i]);
432 			VectorClear (illumination[i]);
433 			continue;
434 		}
435 
436 		for (j=0 ; j<3 ; j++)
437 		{
438 			patch->totallight[j] += illumination[i][j] / patch->area;
439 			radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
440 		}
441 
442 		total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
443 		VectorClear (illumination[i]);
444 	}
445 
446 	return total;
447 }
448 
449 
450 /*
451 =============
452 ShootLight
453 
454 Send light out to other patches
455   Run multi-threaded
456 =============
457 */
ShootLight(int patchnum)458 void ShootLight (int patchnum)
459 {
460 	int			k, l;
461 	transfer_t	*trans;
462 	int			num;
463 	patch_t		*patch;
464 	vec3_t		send;
465 
466 	// this is the amount of light we are distributing
467 	// prescale it so that multiplying by the 16 bit
468 	// transfer values gives a proper output value
469 	for (k=0 ; k<3 ; k++)
470 		send[k] = radiosity[patchnum][k] / 0x10000;
471 	patch = &patches[patchnum];
472 
473 	trans = patch->transfers;
474 	num = patch->numtransfers;
475 
476 	for (k=0 ; k<num ; k++, trans++)
477 	{
478 		for (l=0 ; l<3 ; l++)
479 			illumination[trans->patch][l] += send[l]*trans->transfer;
480 	}
481 }
482 
483 /*
484 =============
485 BounceLight
486 =============
487 */
BounceLight(void)488 void BounceLight (void)
489 {
490 	int		i, j;
491 	float	added;
492 	char	name[64];
493 	patch_t	*p;
494 
495 	for (i=0 ; i<num_patches ; i++)
496 	{
497 		p = &patches[i];
498 		for (j=0 ; j<3 ; j++)
499 		{
500 //			p->totallight[j] = p->samplelight[j];
501 			radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
502 		}
503 	}
504 
505 	for (i=0 ; i<numbounce ; i++)
506 	{
507 		RunThreadsOnIndividual (num_patches, false, ShootLight);
508 		added = CollectLight ();
509 
510 		Sys_FPrintf( SYS_VRB, "bounce:%i added:%f\n", i, added);
511 		if ( dumppatches && (i==0 || i == numbounce-1) )
512 		{
513 			sprintf (name, "bounce%i.txt", i);
514 			WriteWorld (name);
515 		}
516 	}
517 }
518 
519 
520 
521 //==============================================================
522 
CheckPatches(void)523 void CheckPatches (void)
524 {
525 	int		i;
526 	patch_t	*patch;
527 
528 	for (i=0 ; i<num_patches ; i++)
529 	{
530 		patch = &patches[i];
531 		if (patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0)
532 			Error ("negative patch totallight\n");
533 	}
534 }
535 
536 /*
537 =============
538 RadWorld
539 =============
540 */
RadWorld(void)541 void RadWorld (void)
542 {
543 	if (numnodes == 0 || numfaces == 0)
544 		Error ("Empty map");
545 	MakeBackplanes ();
546 	MakeParents (0, -1);
547 	MakeTnodes (&dmodels[0]);
548 
549 	// turn each face into a single patch
550 	MakePatches ();
551 
552 	// subdivide patches to a maximum dimension
553 	SubdividePatches ();
554 
555 	// create directlights out of patches and lights
556 	CreateDirectLights ();
557 
558 	// build initial facelights
559 	RunThreadsOnIndividual (numfaces, true, BuildFacelights);
560 
561 	if (numbounce > 0)
562 	{
563 		// build transfer lists
564 		RunThreadsOnIndividual (num_patches, true, MakeTransfers);
565 		Sys_FPrintf( SYS_VRB, "transfer lists: %5.1f megs\n"
566 		, (float)total_transfer * sizeof(transfer_t) / (1024*1024));
567 
568 		// spread light around
569 		BounceLight ();
570 
571 		FreeTransfers ();
572 
573 		CheckPatches ();
574 	}
575 
576 	if (glview)
577 		WriteGlView ();
578 
579 	// blend bounced light into direct light and save
580 	PairEdges ();
581 	LinkPlaneFaces ();
582 
583 	lightdatasize = 0;
584 	RunThreadsOnIndividual (numfaces, true, FinalLightFace);
585 }
586 
587 
588 /*
589 ========
590 main
591 
592 light modelfile
593 ========
594 */
RAD_Main()595 int RAD_Main ()
596 {
597 	double		start, end;
598 	char		name[1024];
599 	int		total_rad_time;
600 
601 	Sys_Printf ("\n----- RAD ----\n\n");
602 
603 	if (maxlight > 255)
604 		maxlight = 255;
605 
606 	start = I_FloatTime ();
607 
608 	if ( !strcmp( game, "heretic2" ) )
609 		CalcTextureReflectivity = &CalcTextureReflectivity_Heretic2;
610 	else
611 		CalcTextureReflectivity = &CalcTextureReflectivity_Quake2;
612 
613 	SetQdirFromPath (mapname);
614 	strcpy (source, ExpandArg(mapname));
615 	StripExtension (source);
616 	DefaultExtension (source, ".bsp");
617 
618 //	ReadLightFile ();
619 
620 	sprintf (name, "%s%s", inbase, source);
621 	Sys_Printf ("reading %s\n", name);
622 	LoadBSPFile (name);
623 	ParseEntities ();
624 	(*CalcTextureReflectivity) ();
625 
626 	if (!visdatasize)
627 	{
628 		Sys_Printf ("No vis information, direct lighting only.\n");
629 		numbounce = 0;
630 		ambient = 0.1;
631 	}
632 
633 	RadWorld ();
634 
635 	sprintf (name, "%s%s", outbase, source);
636 	Sys_Printf ("writing %s\n", name);
637 	WriteBSPFile (name);
638 
639 	end = I_FloatTime ();
640 	total_rad_time = (int) (end-start);
641 	Sys_Printf("\nRAD Time: ");
642 	if ( total_rad_time > 59 )
643 		Sys_Printf("%d Minutes ", total_rad_time/60 );
644 	Sys_Printf( "%d Seconds\n", total_rad_time%60 );
645 
646 
647 	return 0;
648 }
649 
650