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