]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/q2map/qrad.c
Merge branch 'NateEag-master-patch-12920' into 'master'
[xonotic/netradiant.git] / tools / quake2 / q2map / qrad.c
1 /*
2    Copyright (C) 1999-2007 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];
48 extern char outbase[32];
49
50 int fakeplanes;                         // created planes for origin offset
51
52 int numbounce = 8;
53 qboolean extrasamples;
54
55 float subdiv = 64;
56 qboolean dumppatches;
57
58 void BuildLightmaps( void );
59 int TestLine( vec3_t start, vec3_t stop );
60
61 int junk;
62
63 float ambient = 0;
64 float maxlight = 196;
65
66 float lightscale = 1.0;
67
68 extern qboolean glview;
69
70 qboolean nopvs;
71
72 extern char source[1024];
73
74 float direct_scale =  0.4;
75 float entity_scale =  1.0;
76
77 /*
78    ===================================================================
79
80    MISC
81
82    ===================================================================
83  */
84
85
86 /*
87    =============
88    MakeBackplanes
89    =============
90  */
91 void MakeBackplanes( void ){
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         int i, j;
111         dnode_t *node;
112
113         nodeparents[nodenum] = parent;
114         node = &dnodes[nodenum];
115
116         for ( i = 0 ; i < 2 ; i++ )
117         {
118                 j = node->children[i];
119                 if ( j < 0 ) {
120                         leafparents[-j - 1] = nodenum;
121                 }
122                 else{
123                         MakeParents( j, nodenum );
124                 }
125         }
126 }
127
128
129 /*
130    ===================================================================
131
132    TRANSFER SCALES
133
134    ===================================================================
135  */
136
137 int PointInLeafnum( vec3_t point ){
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                 }
152                 else{
153                         nodenum = node->children[1];
154                 }
155         }
156
157         return -nodenum - 1;
158 }
159
160
161 dleaf_t     *Rad_PointInLeaf( vec3_t point ){
162         int num;
163
164         num = PointInLeafnum( point );
165         return &dleafs[num];
166 }
167
168
169 qboolean PvsForOrigin( vec3_t org, byte *pvs ){
170         dleaf_t *leaf;
171
172         if ( !visdatasize ) {
173                 memset( pvs, 255, ( numleafs + 7 ) / 8 );
174                 return true;
175         }
176
177         leaf = Rad_PointInLeaf( org );
178         if ( leaf->cluster == -1 ) {
179                 return false;       // in solid leaf
180
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         int j;
197         vec3_t delta;
198         vec_t dist, scale;
199         float trans;
200         int itrans;
201         patch_t     *patch, *patch2;
202         float total;
203         dplane_t plane;
204         vec3_t origin;
205         float transfers[MAX_PATCHES], *all_transfers;
206         int s;
207         int itotal;
208         byte pvs[( MAX_MAP_LEAFS + 7 ) / 8];
209         int cluster;
210
211         patch = patches + i;
212         total = 0;
213
214         VectorCopy( patch->origin, origin );
215         plane = *patch->plane;
216
217         if ( !PvsForOrigin( patch->origin, pvs ) ) {
218                 return;
219         }
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
234                 // check pvs bit
235                 if ( !nopvs ) {
236                         cluster = patch2->cluster;
237                         if ( cluster == -1 ) {
238                                 continue;
239                         }
240                         if ( !( pvs[cluster >> 3] & ( 1 << ( cluster & 7 ) ) ) ) {
241                                 continue;       // not in pvs
242                         }
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                 }
252                 // reletive angles
253                 scale = DotProduct( delta, plane.normal );
254                 scale *= -DotProduct( delta, patch2->plane->normal );
255                 if ( scale <= 0 ) {
256                         continue;
257                 }
258
259                 // check exact tramsfer
260                 if ( TestLine_r( 0, patch->origin, patch2->origin ) ) {
261                         continue;
262                 }
263
264                 trans = scale * patch2->area / ( dist * dist );
265
266                 if ( trans < 0 ) {
267                         trans = 0;      // rounding errors...
268
269                 }
270                 transfers[j] = trans;
271                 if ( trans > 0 ) {
272                         total += trans;
273                         patch->numtransfers++;
274                 }
275         }
276
277         // copy the transfers out and normalize
278         // total should be somewhere near PI if everything went right
279         // because partial occlusion isn't accounted for, and nearby
280         // patches have underestimated form factors, it will usually
281         // be higher than PI
282         if ( patch->numtransfers ) {
283                 transfer_t  *t;
284
285                 if ( patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES ) {
286                         Error( "Weird numtransfers" );
287                 }
288                 s = patch->numtransfers * sizeof( transfer_t );
289                 patch->transfers = malloc( s );
290                 if ( !patch->transfers ) {
291                         Error( "Memory allocation failure" );
292                 }
293
294                 //
295                 // normalize all transfers so all of the light
296                 // is transfered to the surroundings
297                 //
298                 t = patch->transfers;
299                 itotal = 0;
300                 for ( j = 0 ; j < num_patches ; j++ )
301                 {
302                         if ( transfers[j] <= 0 ) {
303                                 continue;
304                         }
305                         itrans = transfers[j] * 0x10000 / total;
306                         itotal += itrans;
307                         t->transfer = itrans;
308                         t->patch = j;
309                         t++;
310                 }
311         }
312
313         // don't bother locking around this.  not that important.
314         total_transfer += patch->numtransfers;
315 }
316
317
318 /*
319    =============
320    FreeTransfers
321    =============
322  */
323 void FreeTransfers( void ){
324         int i;
325
326         for ( i = 0 ; i < num_patches ; i++ )
327         {
328                 free( patches[i].transfers );
329                 patches[i].transfers = NULL;
330         }
331 }
332
333
334 //===================================================================
335
336 /*
337    =============
338    WriteWorld
339    =============
340  */
341 void WriteWorld( char *name ){
342         int i, j;
343         FILE        *out;
344         patch_t     *patch;
345         winding_t   *w;
346
347         out = fopen( name, "w" );
348         if ( !out ) {
349                 Error( "Couldn't open %s", name );
350         }
351
352         for ( j = 0, patch = patches ; j < num_patches ; j++, patch++ )
353         {
354                 w = patch->winding;
355                 fprintf( out, "%i\n", w->numpoints );
356                 for ( i = 0 ; i < w->numpoints ; i++ )
357                 {
358                         fprintf( out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
359                                          w->p[i][0],
360                                          w->p[i][1],
361                                          w->p[i][2],
362                                          patch->totallight[0],
363                                          patch->totallight[1],
364                                          patch->totallight[2] );
365                 }
366                 fprintf( out, "\n" );
367         }
368
369         fclose( out );
370 }
371
372 /*
373    =============
374    WriteGlView
375    =============
376  */
377 void WriteGlView( void ){
378         char name[1024];
379         FILE    *f;
380         int i, j;
381         patch_t *p;
382         winding_t   *w;
383
384         strcpy( name, source );
385         StripExtension( name );
386         strcat( name, ".glr" );
387
388         f = fopen( name, "w" );
389         if ( !f ) {
390                 Error( "Couldn't open %s", f );
391         }
392
393         for ( j = 0 ; j < num_patches ; j++ )
394         {
395                 p = &patches[j];
396                 w = p->winding;
397                 fprintf( f, "%i\n", w->numpoints );
398                 for ( i = 0 ; i < w->numpoints ; i++ )
399                 {
400                         fprintf( f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
401                                          w->p[i][0],
402                                          w->p[i][1],
403                                          w->p[i][2],
404                                          p->totallight[0] / 128,
405                                          p->totallight[1] / 128,
406                                          p->totallight[2] / 128 );
407                 }
408                 fprintf( f, "\n" );
409         }
410
411         fclose( f );
412 }
413
414
415 //==============================================================
416
417 /*
418    =============
419    CollectLight
420    =============
421  */
422 float CollectLight( void ){
423         int i, j;
424         patch_t *patch;
425         vec_t total;
426
427         total = 0;
428
429         for ( i = 0, patch = patches ; i < num_patches ; i++, patch++ )
430         {
431                 // skys never collect light, it is just dropped
432                 if ( patch->sky ) {
433                         VectorClear( radiosity[i] );
434                         VectorClear( illumination[i] );
435                         continue;
436                 }
437
438                 for ( j = 0 ; j < 3 ; j++ )
439                 {
440                         patch->totallight[j] += illumination[i][j] / patch->area;
441                         radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
442                 }
443
444                 total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
445                 VectorClear( illumination[i] );
446         }
447
448         return total;
449 }
450
451
452 /*
453    =============
454    ShootLight
455
456    Send light out to other patches
457    Run multi-threaded
458    =============
459  */
460 void ShootLight( int patchnum ){
461         int k, l;
462         transfer_t  *trans;
463         int num;
464         patch_t     *patch;
465         vec3_t send;
466
467         // this is the amount of light we are distributing
468         // prescale it so that multiplying by the 16 bit
469         // transfer values gives a proper output value
470         for ( k = 0 ; k < 3 ; k++ )
471                 send[k] = radiosity[patchnum][k] / 0x10000;
472         patch = &patches[patchnum];
473
474         trans = patch->transfers;
475         num = patch->numtransfers;
476
477         for ( k = 0 ; k < num ; k++, trans++ )
478         {
479                 for ( l = 0 ; l < 3 ; l++ )
480                         illumination[trans->patch][l] += send[l] * trans->transfer;
481         }
482 }
483
484 /*
485    =============
486    BounceLight
487    =============
488  */
489 void BounceLight( void ){
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                         sprintf( name, "bounce%i.txt", i );
513                         WriteWorld( name );
514                 }
515         }
516 }
517
518
519
520 //==============================================================
521
522 void CheckPatches( void ){
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    =============
537    RadWorld
538    =============
539  */
540 void RadWorld( void ){
541         if ( numnodes == 0 || numfaces == 0 ) {
542                 Error( "Empty map" );
543         }
544         MakeBackplanes();
545         MakeParents( 0, -1 );
546         MakeTnodes( &dmodels[0] );
547
548         // turn each face into a single patch
549         MakePatches();
550
551         // subdivide patches to a maximum dimension
552         SubdividePatches();
553
554         // create directlights out of patches and lights
555         CreateDirectLights();
556
557         // build initial facelights
558         RunThreadsOnIndividual( numfaces, true, BuildFacelights );
559
560         if ( numbounce > 0 ) {
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
578         // blend bounced light into direct light and save
579         PairEdges();
580         LinkPlaneFaces();
581
582         lightdatasize = 0;
583         RunThreadsOnIndividual( numfaces, true, FinalLightFace );
584 }
585
586 /*
587    ========
588    main
589
590    light modelfile
591    ========
592  */
593 int RAD_Main(){
594         double start, end;
595         char name[1024];
596         int total_rad_time;
597
598         Sys_Printf( "\n----- RAD ----\n\n" );
599
600         if ( maxlight > 255 ) {
601                 maxlight = 255;
602         }
603
604         start = I_FloatTime();
605
606         void ( *CalcTextureReflectivity )( void );
607
608         if ( !strcmp( game, "heretic2" ) ) {
609                 CalcTextureReflectivity = &CalcTextureReflectivity_Heretic2;
610         }
611         else{
612                 CalcTextureReflectivity = &CalcTextureReflectivity_Quake2;
613         }
614
615         SetQdirFromPath( mapname );
616         strcpy( source, ExpandArg( mapname ) );
617         StripExtension( source );
618         DefaultExtension( source, ".bsp" );
619
620 //      ReadLightFile ();
621
622         sprintf( name, "%s%s", inbase, source );
623         Sys_Printf( "reading %s\n", name );
624         LoadBSPFile( name );
625         ParseEntities();
626         ( *CalcTextureReflectivity )( );
627
628         if ( !visdatasize ) {
629                 Sys_Printf( "No vis information, direct lighting only.\n" );
630                 numbounce = 0;
631                 ambient = 0.1;
632         }
633
634         RadWorld();
635
636         sprintf( name, "%s%s", outbase, source );
637         Sys_Printf( "writing %s\n", name );
638         WriteBSPFile( name );
639
640         end = I_FloatTime();
641         total_rad_time = (int) ( end - start );
642         Sys_Printf( "\nRAD Time: " );
643         if ( total_rad_time > 59 ) {
644                 Sys_Printf( "%d Minutes ", total_rad_time / 60 );
645         }
646         Sys_Printf( "%d Seconds\n", total_rad_time % 60 );
647
648
649         return 0;
650 }