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 char inbase[32], outbase[32];
49 int fakeplanes; // created planes for origin offset
52 qboolean extrasamples;
57 void BuildLightmaps( void );
58 int TestLine( vec3_t start, vec3_t stop );
65 float lightscale = 1.0;
73 float direct_scale = 0.4;
74 float entity_scale = 1.0;
77 ===================================================================
81 ===================================================================
90 void MakeBackplanes( void ){
93 for ( i = 0 ; i < numplanes ; i++ )
95 backplanes[i].dist = -dplanes[i].dist;
96 VectorSubtract( vec3_origin, dplanes[i].normal, backplanes[i].normal );
100 int leafparents[MAX_MAP_LEAFS];
101 int nodeparents[MAX_MAP_NODES];
108 void MakeParents( int nodenum, int parent ){
112 nodeparents[nodenum] = parent;
113 node = &dnodes[nodenum];
115 for ( i = 0 ; i < 2 ; i++ )
117 j = node->children[i];
119 leafparents[-j - 1] = nodenum;
122 MakeParents( j, nodenum );
129 ===================================================================
133 ===================================================================
136 int PointInLeafnum( vec3_t point ){
143 while ( nodenum >= 0 )
145 node = &dnodes[nodenum];
146 plane = &dplanes[node->planenum];
147 dist = DotProduct( point, plane->normal ) - plane->dist;
149 nodenum = node->children[0];
152 nodenum = node->children[1];
160 dleaf_t *Rad_PointInLeaf( vec3_t point ){
163 num = PointInLeafnum( point );
168 qboolean PvsForOrigin( vec3_t org, byte *pvs ){
171 if ( !visdatasize ) {
172 memset( pvs, 255, ( numleafs + 7 ) / 8 );
176 leaf = Rad_PointInLeaf( org );
177 if ( leaf->cluster == -1 ) {
178 return false; // in solid leaf
181 DecompressVis( dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs );
194 void MakeTransfers( int i ){
200 patch_t *patch, *patch2;
204 float transfers[MAX_PATCHES], *all_transfers;
207 byte pvs[( MAX_MAP_LEAFS + 7 ) / 8];
213 VectorCopy( patch->origin, origin );
214 plane = *patch->plane;
216 if ( !PvsForOrigin( patch->origin, pvs ) ) {
220 // find out which patch2s will collect light
223 all_transfers = transfers;
224 patch->numtransfers = 0;
225 for ( j = 0, patch2 = patches ; j < num_patches ; j++, patch2++ )
235 cluster = patch2->cluster;
236 if ( cluster == -1 ) {
239 if ( !( pvs[cluster >> 3] & ( 1 << ( cluster & 7 ) ) ) ) {
240 continue; // not in pvs
245 VectorSubtract( patch2->origin, origin, delta );
246 dist = VectorNormalize( delta, delta );
248 continue; // should never happen
252 scale = DotProduct( delta, plane.normal );
253 scale *= -DotProduct( delta, patch2->plane->normal );
258 // check exact tramsfer
259 if ( TestLine_r( 0, patch->origin, patch2->origin ) ) {
263 trans = scale * patch2->area / ( dist * dist );
266 trans = 0; // rounding errors...
269 transfers[j] = trans;
272 patch->numtransfers++;
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
281 if ( patch->numtransfers ) {
284 if ( patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES ) {
285 Error( "Weird numtransfers" );
287 s = patch->numtransfers * sizeof( transfer_t );
288 patch->transfers = malloc( s );
289 if ( !patch->transfers ) {
290 Error( "Memory allocation failure" );
294 // normalize all transfers so all of the light
295 // is transfered to the surroundings
297 t = patch->transfers;
299 for ( j = 0 ; j < num_patches ; j++ )
301 if ( transfers[j] <= 0 ) {
304 itrans = transfers[j] * 0x10000 / total;
306 t->transfer = itrans;
312 // don't bother locking around this. not that important.
313 total_transfer += patch->numtransfers;
322 void FreeTransfers( void ){
325 for ( i = 0 ; i < num_patches ; i++ )
327 free( patches[i].transfers );
328 patches[i].transfers = NULL;
333 //===================================================================
340 void WriteWorld( char *name ){
346 out = fopen( name, "w" );
348 Error( "Couldn't open %s", name );
351 for ( j = 0, patch = patches ; j < num_patches ; j++, patch++ )
354 fprintf( out, "%i\n", w->numpoints );
355 for ( i = 0 ; i < w->numpoints ; i++ )
357 fprintf( out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
361 patch->totallight[0],
362 patch->totallight[1],
363 patch->totallight[2] );
365 fprintf( out, "\n" );
376 void WriteGlView( void ){
383 strcpy( name, source );
384 StripExtension( name );
385 strcat( name, ".glr" );
387 f = fopen( name, "w" );
389 Error( "Couldn't open %s", f );
392 for ( j = 0 ; j < num_patches ; j++ )
396 fprintf( f, "%i\n", w->numpoints );
397 for ( i = 0 ; i < w->numpoints ; i++ )
399 fprintf( f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
403 p->totallight[0] / 128,
404 p->totallight[1] / 128,
405 p->totallight[2] / 128 );
414 //==============================================================
421 float CollectLight( void ){
428 for ( i = 0, patch = patches ; i < num_patches ; i++, patch++ )
430 // skys never collect light, it is just dropped
432 VectorClear( radiosity[i] );
433 VectorClear( illumination[i] );
437 for ( j = 0 ; j < 3 ; j++ )
439 patch->totallight[j] += illumination[i][j] / patch->area;
440 radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
443 total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
444 VectorClear( illumination[i] );
455 Send light out to other patches
459 void ShootLight( int patchnum ){
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];
473 trans = patch->transfers;
474 num = patch->numtransfers;
476 for ( k = 0 ; k < num ; k++, trans++ )
478 for ( l = 0 ; l < 3 ; l++ )
479 illumination[trans->patch][l] += send[l] * trans->transfer;
488 void BounceLight( void ){
494 for ( i = 0 ; i < num_patches ; i++ )
497 for ( j = 0 ; j < 3 ; j++ )
499 // p->totallight[j] = p->samplelight[j];
500 radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
504 for ( i = 0 ; i < numbounce ; i++ )
506 RunThreadsOnIndividual( num_patches, false, ShootLight );
507 added = CollectLight();
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 );
519 //==============================================================
521 void CheckPatches( void ){
525 for ( i = 0 ; i < num_patches ; i++ )
528 if ( patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0 ) {
529 Error( "negative patch totallight\n" );
539 void RadWorld( void ){
540 if ( numnodes == 0 || numfaces == 0 ) {
541 Error( "Empty map" );
544 MakeParents( 0, -1 );
545 MakeTnodes( &dmodels[0] );
547 // turn each face into a single patch
550 // subdivide patches to a maximum dimension
553 // create directlights out of patches and lights
554 CreateDirectLights();
556 // build initial facelights
557 RunThreadsOnIndividual( numfaces, true, BuildFacelights );
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 ) );
565 // spread light around
577 // blend bounced light into direct light and save
582 RunThreadsOnIndividual( numfaces, true, FinalLightFace );
598 Sys_Printf( "\n----- RAD ----\n\n" );
600 if ( maxlight > 255 ) {
604 start = I_FloatTime();
606 if ( !strcmp( game, "heretic2" ) ) {
607 CalcTextureReflectivity = &CalcTextureReflectivity_Heretic2;
610 CalcTextureReflectivity = &CalcTextureReflectivity_Quake2;
613 SetQdirFromPath( mapname );
614 strcpy( source, ExpandArg( mapname ) );
615 StripExtension( source );
616 DefaultExtension( source, ".bsp" );
620 sprintf( name, "%s%s", inbase, source );
621 Sys_Printf( "reading %s\n", name );
624 ( *CalcTextureReflectivity )( );
626 if ( !visdatasize ) {
627 Sys_Printf( "No vis information, direct lighting only.\n" );
634 sprintf( name, "%s%s", outbase, source );
635 Sys_Printf( "writing %s\n", name );
636 WriteBSPFile( name );
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 );
644 Sys_Printf( "%d Seconds\n", total_rad_time % 60 );