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