]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/q2map/qrad.c
my own uncrustify run
[xonotic/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         int i;
92
93         for ( i = 0 ; i < numplanes ; i++ )
94         {
95                 backplanes[i].dist = -dplanes[i].dist;
96                 VectorSubtract( vec3_origin, dplanes[i].normal, backplanes[i].normal );
97         }
98 }
99
100 int leafparents[MAX_MAP_LEAFS];
101 int nodeparents[MAX_MAP_NODES];
102
103 /*
104    =============
105    MakeParents
106    =============
107  */
108 void MakeParents( int nodenum, int parent ){
109         int i, j;
110         dnode_t *node;
111
112         nodeparents[nodenum] = parent;
113         node = &dnodes[nodenum];
114
115         for ( i = 0 ; i < 2 ; i++ )
116         {
117                 j = node->children[i];
118                 if ( j < 0 ) {
119                         leafparents[-j - 1] = nodenum;
120                 }
121                 else{
122                         MakeParents( j, nodenum );
123                 }
124         }
125 }
126
127
128 /*
129    ===================================================================
130
131    TRANSFER SCALES
132
133    ===================================================================
134  */
135
136 int PointInLeafnum( vec3_t point ){
137         int nodenum;
138         vec_t dist;
139         dnode_t *node;
140         dplane_t    *plane;
141
142         nodenum = 0;
143         while ( nodenum >= 0 )
144         {
145                 node = &dnodes[nodenum];
146                 plane = &dplanes[node->planenum];
147                 dist = DotProduct( point, plane->normal ) - plane->dist;
148                 if ( dist > 0 ) {
149                         nodenum = node->children[0];
150                 }
151                 else{
152                         nodenum = node->children[1];
153                 }
154         }
155
156         return -nodenum - 1;
157 }
158
159
160 dleaf_t     *Rad_PointInLeaf( vec3_t point ){
161         int num;
162
163         num = PointInLeafnum( point );
164         return &dleafs[num];
165 }
166
167
168 qboolean PvsForOrigin( vec3_t org, byte *pvs ){
169         dleaf_t *leaf;
170
171         if ( !visdatasize ) {
172                 memset( pvs, 255, ( numleafs + 7 ) / 8 );
173                 return true;
174         }
175
176         leaf = Rad_PointInLeaf( org );
177         if ( leaf->cluster == -1 ) {
178                 return false;       // in solid leaf
179
180         }
181         DecompressVis( dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs );
182         return true;
183 }
184
185
186 /*
187    =============
188    MakeTransfers
189
190    =============
191  */
192 int total_transfer;
193
194 void MakeTransfers( int i ){
195         int j;
196         vec3_t delta;
197         vec_t dist, scale;
198         float trans;
199         int itrans;
200         patch_t     *patch, *patch2;
201         float total;
202         dplane_t plane;
203         vec3_t origin;
204         float transfers[MAX_PATCHES], *all_transfers;
205         int s;
206         int itotal;
207         byte pvs[( MAX_MAP_LEAFS + 7 ) / 8];
208         int cluster;
209
210         patch = patches + i;
211         total = 0;
212
213         VectorCopy( patch->origin, origin );
214         plane = *patch->plane;
215
216         if ( !PvsForOrigin( patch->origin, pvs ) ) {
217                 return;
218         }
219
220         // find out which patch2s will collect light
221         // from patch
222
223         all_transfers = transfers;
224         patch->numtransfers = 0;
225         for ( j = 0, patch2 = patches ; j < num_patches ; j++, patch2++ )
226         {
227                 transfers[j] = 0;
228
229                 if ( j == i ) {
230                         continue;
231                 }
232
233                 // check pvs bit
234                 if ( !nopvs ) {
235                         cluster = patch2->cluster;
236                         if ( cluster == -1 ) {
237                                 continue;
238                         }
239                         if ( !( pvs[cluster >> 3] & ( 1 << ( cluster & 7 ) ) ) ) {
240                                 continue;       // not in pvs
241                         }
242                 }
243
244                 // calculate vector
245                 VectorSubtract( patch2->origin, origin, delta );
246                 dist = VectorNormalize( delta, delta );
247                 if ( !dist ) {
248                         continue;   // should never happen
249
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
258                 // check exact tramsfer
259                 if ( TestLine_r( 0, patch->origin, patch2->origin ) ) {
260                         continue;
261                 }
262
263                 trans = scale * patch2->area / ( dist * dist );
264
265                 if ( trans < 0 ) {
266                         trans = 0;      // rounding errors...
267
268                 }
269                 transfers[j] = trans;
270                 if ( trans > 0 ) {
271                         total += trans;
272                         patch->numtransfers++;
273                 }
274         }
275
276         // copy the transfers out and normalize
277         // total should be somewhere near PI if everything went right
278         // because partial occlusion isn't accounted for, and nearby
279         // patches have underestimated form factors, it will usually
280         // be higher than PI
281         if ( patch->numtransfers ) {
282                 transfer_t  *t;
283
284                 if ( patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES ) {
285                         Error( "Weird numtransfers" );
286                 }
287                 s = patch->numtransfers * sizeof( transfer_t );
288                 patch->transfers = malloc( s );
289                 if ( !patch->transfers ) {
290                         Error( "Memory allocation failure" );
291                 }
292
293                 //
294                 // normalize all transfers so all of the light
295                 // is transfered to the surroundings
296                 //
297                 t = patch->transfers;
298                 itotal = 0;
299                 for ( j = 0 ; j < num_patches ; j++ )
300                 {
301                         if ( transfers[j] <= 0 ) {
302                                 continue;
303                         }
304                         itrans = transfers[j] * 0x10000 / total;
305                         itotal += itrans;
306                         t->transfer = itrans;
307                         t->patch = j;
308                         t++;
309                 }
310         }
311
312         // don't bother locking around this.  not that important.
313         total_transfer += patch->numtransfers;
314 }
315
316
317 /*
318    =============
319    FreeTransfers
320    =============
321  */
322 void FreeTransfers( void ){
323         int i;
324
325         for ( i = 0 ; i < num_patches ; i++ )
326         {
327                 free( patches[i].transfers );
328                 patches[i].transfers = NULL;
329         }
330 }
331
332
333 //===================================================================
334
335 /*
336    =============
337    WriteWorld
338    =============
339  */
340 void WriteWorld( char *name ){
341         int i, j;
342         FILE        *out;
343         patch_t     *patch;
344         winding_t   *w;
345
346         out = fopen( name, "w" );
347         if ( !out ) {
348                 Error( "Couldn't open %s", name );
349         }
350
351         for ( j = 0, patch = patches ; j < num_patches ; j++, patch++ )
352         {
353                 w = patch->winding;
354                 fprintf( out, "%i\n", w->numpoints );
355                 for ( i = 0 ; i < w->numpoints ; i++ )
356                 {
357                         fprintf( out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
358                                          w->p[i][0],
359                                          w->p[i][1],
360                                          w->p[i][2],
361                                          patch->totallight[0],
362                                          patch->totallight[1],
363                                          patch->totallight[2] );
364                 }
365                 fprintf( out, "\n" );
366         }
367
368         fclose( out );
369 }
370
371 /*
372    =============
373    WriteGlView
374    =============
375  */
376 void WriteGlView( void ){
377         char name[1024];
378         FILE    *f;
379         int i, j;
380         patch_t *p;
381         winding_t   *w;
382
383         strcpy( name, source );
384         StripExtension( name );
385         strcat( name, ".glr" );
386
387         f = fopen( name, "w" );
388         if ( !f ) {
389                 Error( "Couldn't open %s", f );
390         }
391
392         for ( j = 0 ; j < num_patches ; j++ )
393         {
394                 p = &patches[j];
395                 w = p->winding;
396                 fprintf( f, "%i\n", w->numpoints );
397                 for ( i = 0 ; i < w->numpoints ; i++ )
398                 {
399                         fprintf( f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
400                                          w->p[i][0],
401                                          w->p[i][1],
402                                          w->p[i][2],
403                                          p->totallight[0] / 128,
404                                          p->totallight[1] / 128,
405                                          p->totallight[2] / 128 );
406                 }
407                 fprintf( f, "\n" );
408         }
409
410         fclose( f );
411 }
412
413
414 //==============================================================
415
416 /*
417    =============
418    CollectLight
419    =============
420  */
421 float CollectLight( void ){
422         int i, j;
423         patch_t *patch;
424         vec_t total;
425
426         total = 0;
427
428         for ( i = 0, patch = patches ; i < num_patches ; i++, patch++ )
429         {
430                 // skys never collect light, it is just dropped
431                 if ( patch->sky ) {
432                         VectorClear( radiosity[i] );
433                         VectorClear( illumination[i] );
434                         continue;
435                 }
436
437                 for ( j = 0 ; j < 3 ; j++ )
438                 {
439                         patch->totallight[j] += illumination[i][j] / patch->area;
440                         radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
441                 }
442
443                 total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
444                 VectorClear( illumination[i] );
445         }
446
447         return total;
448 }
449
450
451 /*
452    =============
453    ShootLight
454
455    Send light out to other patches
456    Run multi-threaded
457    =============
458  */
459 void ShootLight( int patchnum ){
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  */
488 void BounceLight( void ){
489         int i, j;
490         float added;
491         char name[64];
492         patch_t *p;
493
494         for ( i = 0 ; i < num_patches ; i++ )
495         {
496                 p = &patches[i];
497                 for ( j = 0 ; j < 3 ; j++ )
498                 {
499 //                      p->totallight[j] = p->samplelight[j];
500                         radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
501                 }
502         }
503
504         for ( i = 0 ; i < numbounce ; i++ )
505         {
506                 RunThreadsOnIndividual( num_patches, false, ShootLight );
507                 added = CollectLight();
508
509                 Sys_FPrintf( SYS_VRB, "bounce:%i added:%f\n", i, added );
510                 if ( dumppatches && ( i == 0 || i == numbounce - 1 ) ) {
511                         sprintf( name, "bounce%i.txt", i );
512                         WriteWorld( name );
513                 }
514         }
515 }
516
517
518
519 //==============================================================
520
521 void CheckPatches( void ){
522         int i;
523         patch_t *patch;
524
525         for ( i = 0 ; i < num_patches ; i++ )
526         {
527                 patch = &patches[i];
528                 if ( patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0 ) {
529                         Error( "negative patch totallight\n" );
530                 }
531         }
532 }
533
534 /*
535    =============
536    RadWorld
537    =============
538  */
539 void RadWorld( void ){
540         if ( numnodes == 0 || numfaces == 0 ) {
541                 Error( "Empty map" );
542         }
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                 // build transfer lists
561                 RunThreadsOnIndividual( num_patches, true, MakeTransfers );
562                 Sys_FPrintf( SYS_VRB, "transfer lists: %5.1f megs\n"
563                                          , (float)total_transfer * sizeof( transfer_t ) / ( 1024 * 1024 ) );
564
565                 // spread light around
566                 BounceLight();
567
568                 FreeTransfers();
569
570                 CheckPatches();
571         }
572
573         if ( glview ) {
574                 WriteGlView();
575         }
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         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         if ( !strcmp( game, "heretic2" ) ) {
607                 CalcTextureReflectivity = &CalcTextureReflectivity_Heretic2;
608         }
609         else{
610                 CalcTextureReflectivity = &CalcTextureReflectivity_Quake2;
611         }
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                 Sys_Printf( "No vis information, direct lighting only.\n" );
628                 numbounce = 0;
629                 ambient = 0.1;
630         }
631
632         RadWorld();
633
634         sprintf( name, "%s%s", outbase, source );
635         Sys_Printf( "writing %s\n", name );
636         WriteBSPFile( name );
637
638         end = I_FloatTime();
639         total_rad_time = (int) ( end - start );
640         Sys_Printf( "\nRAD Time: " );
641         if ( total_rad_time > 59 ) {
642                 Sys_Printf( "%d Minutes ", total_rad_time / 60 );
643         }
644         Sys_Printf( "%d Seconds\n", total_rad_time % 60 );
645
646
647         return 0;
648 }