2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
32 every surface must be divided into at least two patches each axis
36 patch_t *face_patches[MAX_MAP_FACES];
37 entity_t *face_entity[MAX_MAP_FACES];
38 patch_t patches[MAX_PATCHES];
41 vec3_t radiosity[MAX_PATCHES]; // light leaving a patch
42 vec3_t illumination[MAX_PATCHES]; // light arriving at a patch
44 vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels
45 dplane_t backplanes[MAX_MAP_PLANES];
47 extern char inbase[32];
48 extern char outbase[32];
50 int fakeplanes; // created planes for origin offset
53 qboolean extrasamples;
58 void BuildLightmaps( void );
59 int TestLine( vec3_t start, vec3_t stop );
66 float lightscale = 1.0;
68 extern qboolean glview;
72 extern char source[1024];
74 float direct_scale = 0.4;
75 float entity_scale = 1.0;
78 ===================================================================
82 ===================================================================
91 void MakeBackplanes( void ){
94 for ( i = 0 ; i < numplanes ; i++ )
96 backplanes[i].dist = -dplanes[i].dist;
97 VectorSubtract( vec3_origin, dplanes[i].normal, backplanes[i].normal );
101 int leafparents[MAX_MAP_LEAFS];
102 int nodeparents[MAX_MAP_NODES];
109 void MakeParents( int nodenum, int parent ){
113 nodeparents[nodenum] = parent;
114 node = &dnodes[nodenum];
116 for ( i = 0 ; i < 2 ; i++ )
118 j = node->children[i];
120 leafparents[-j - 1] = nodenum;
123 MakeParents( j, nodenum );
130 ===================================================================
134 ===================================================================
137 int PointInLeafnum( vec3_t point ){
144 while ( nodenum >= 0 )
146 node = &dnodes[nodenum];
147 plane = &dplanes[node->planenum];
148 dist = DotProduct( point, plane->normal ) - plane->dist;
150 nodenum = node->children[0];
153 nodenum = node->children[1];
161 dleaf_t *Rad_PointInLeaf( vec3_t point ){
164 num = PointInLeafnum( point );
169 qboolean PvsForOrigin( vec3_t org, byte *pvs ){
172 if ( !visdatasize ) {
173 memset( pvs, 255, ( numleafs + 7 ) / 8 );
177 leaf = Rad_PointInLeaf( org );
178 if ( leaf->cluster == -1 ) {
179 return false; // in solid leaf
182 DecompressVis( dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs );
195 void MakeTransfers( int i ){
201 patch_t *patch, *patch2;
205 float transfers[MAX_PATCHES], *all_transfers;
208 byte pvs[( MAX_MAP_LEAFS + 7 ) / 8];
214 VectorCopy( patch->origin, origin );
215 plane = *patch->plane;
217 if ( !PvsForOrigin( patch->origin, pvs ) ) {
221 // find out which patch2s will collect light
224 all_transfers = transfers;
225 patch->numtransfers = 0;
226 for ( j = 0, patch2 = patches ; j < num_patches ; j++, patch2++ )
236 cluster = patch2->cluster;
237 if ( cluster == -1 ) {
240 if ( !( pvs[cluster >> 3] & ( 1 << ( cluster & 7 ) ) ) ) {
241 continue; // not in pvs
246 VectorSubtract( patch2->origin, origin, delta );
247 dist = VectorNormalize( delta, delta );
249 continue; // should never happen
253 scale = DotProduct( delta, plane.normal );
254 scale *= -DotProduct( delta, patch2->plane->normal );
259 // check exact tramsfer
260 if ( TestLine_r( 0, patch->origin, patch2->origin ) ) {
264 trans = scale * patch2->area / ( dist * dist );
267 trans = 0; // rounding errors...
270 transfers[j] = trans;
273 patch->numtransfers++;
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
282 if ( patch->numtransfers ) {
285 if ( patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES ) {
286 Error( "Weird numtransfers" );
288 s = patch->numtransfers * sizeof( transfer_t );
289 patch->transfers = malloc( s );
290 if ( !patch->transfers ) {
291 Error( "Memory allocation failure" );
295 // normalize all transfers so all of the light
296 // is transfered to the surroundings
298 t = patch->transfers;
300 for ( j = 0 ; j < num_patches ; j++ )
302 if ( transfers[j] <= 0 ) {
305 itrans = transfers[j] * 0x10000 / total;
307 t->transfer = itrans;
313 // don't bother locking around this. not that important.
314 total_transfer += patch->numtransfers;
323 void FreeTransfers( void ){
326 for ( i = 0 ; i < num_patches ; i++ )
328 free( patches[i].transfers );
329 patches[i].transfers = NULL;
334 //===================================================================
341 void WriteWorld( char *name ){
347 out = fopen( name, "w" );
349 Error( "Couldn't open %s", name );
352 for ( j = 0, patch = patches ; j < num_patches ; j++, patch++ )
355 fprintf( out, "%i\n", w->numpoints );
356 for ( i = 0 ; i < w->numpoints ; i++ )
358 fprintf( out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
362 patch->totallight[0],
363 patch->totallight[1],
364 patch->totallight[2] );
366 fprintf( out, "\n" );
377 void WriteGlView( void ){
384 strcpy( name, source );
385 StripExtension( name );
386 strcat( name, ".glr" );
388 f = fopen( name, "w" );
390 Error( "Couldn't open %s", f );
393 for ( j = 0 ; j < num_patches ; j++ )
397 fprintf( f, "%i\n", w->numpoints );
398 for ( i = 0 ; i < w->numpoints ; i++ )
400 fprintf( f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
404 p->totallight[0] / 128,
405 p->totallight[1] / 128,
406 p->totallight[2] / 128 );
415 //==============================================================
422 float CollectLight( void ){
429 for ( i = 0, patch = patches ; i < num_patches ; i++, patch++ )
431 // skys never collect light, it is just dropped
433 VectorClear( radiosity[i] );
434 VectorClear( illumination[i] );
438 for ( j = 0 ; j < 3 ; j++ )
440 patch->totallight[j] += illumination[i][j] / patch->area;
441 radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
444 total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
445 VectorClear( illumination[i] );
456 Send light out to other patches
460 void ShootLight( int patchnum ){
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];
474 trans = patch->transfers;
475 num = patch->numtransfers;
477 for ( k = 0 ; k < num ; k++, trans++ )
479 for ( l = 0 ; l < 3 ; l++ )
480 illumination[trans->patch][l] += send[l] * trans->transfer;
489 void BounceLight( void ){
495 for ( i = 0 ; i < num_patches ; i++ )
498 for ( j = 0 ; j < 3 ; j++ )
500 // p->totallight[j] = p->samplelight[j];
501 radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
505 for ( i = 0 ; i < numbounce ; i++ )
507 RunThreadsOnIndividual( num_patches, false, ShootLight );
508 added = CollectLight();
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 );
520 //==============================================================
522 void CheckPatches( void ){
526 for ( i = 0 ; i < num_patches ; i++ )
529 if ( patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0 ) {
530 Error( "negative patch totallight\n" );
540 void RadWorld( void ){
541 if ( numnodes == 0 || numfaces == 0 ) {
542 Error( "Empty map" );
545 MakeParents( 0, -1 );
546 MakeTnodes( &dmodels[0] );
548 // turn each face into a single patch
551 // subdivide patches to a maximum dimension
554 // create directlights out of patches and lights
555 CreateDirectLights();
557 // build initial facelights
558 RunThreadsOnIndividual( numfaces, true, BuildFacelights );
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 ) );
566 // spread light around
578 // blend bounced light into direct light and save
583 RunThreadsOnIndividual( numfaces, true, FinalLightFace );
598 Sys_Printf( "\n----- RAD ----\n\n" );
600 if ( maxlight > 255 ) {
604 start = I_FloatTime();
606 void ( *CalcTextureReflectivity )( void );
608 if ( !strcmp( game, "heretic2" ) ) {
609 CalcTextureReflectivity = &CalcTextureReflectivity_Heretic2;
612 CalcTextureReflectivity = &CalcTextureReflectivity_Quake2;
615 SetQdirFromPath( mapname );
616 strcpy( source, ExpandArg( mapname ) );
617 StripExtension( source );
618 DefaultExtension( source, ".bsp" );
622 sprintf( name, "%s%s", inbase, source );
623 Sys_Printf( "reading %s\n", name );
626 ( *CalcTextureReflectivity )( );
628 if ( !visdatasize ) {
629 Sys_Printf( "No vis information, direct lighting only.\n" );
636 sprintf( name, "%s%s", outbase, source );
637 Sys_Printf( "writing %s\n", name );
638 WriteBSPFile( name );
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 );
646 Sys_Printf( "%d Seconds\n", total_rad_time % 60 );