2 Copyright (C) 1999-2006 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)
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)
114 nodeparents[nodenum] = parent;
115 node = &dnodes[nodenum];
117 for (i=0 ; i<2 ; i++)
119 j = node->children[i];
121 leafparents[-j - 1] = nodenum;
123 MakeParents (j, nodenum);
129 ===================================================================
133 ===================================================================
136 int PointInLeafnum (vec3_t point)
146 node = &dnodes[nodenum];
147 plane = &dplanes[node->planenum];
148 dist = DotProduct (point, plane->normal) - plane->dist;
150 nodenum = node->children[0];
152 nodenum = node->children[1];
159 dleaf_t *Rad_PointInLeaf (vec3_t point)
163 num = PointInLeafnum (point);
168 qboolean PvsForOrigin (vec3_t org, byte *pvs)
174 memset (pvs, 255, (numleafs+7)/8 );
178 leaf = Rad_PointInLeaf (org);
179 if (leaf->cluster == -1)
180 return false; // in solid leaf
182 DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs);
195 void MakeTransfers (int i)
202 patch_t *patch, *patch2;
206 float transfers[MAX_PATCHES], *all_transfers;
209 byte pvs[(MAX_MAP_LEAFS+7)/8];
215 VectorCopy (patch->origin, origin);
216 plane = *patch->plane;
218 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;
239 if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) )
240 continue; // not in pvs
244 VectorSubtract (patch2->origin, origin, delta);
245 dist = VectorNormalize (delta, delta);
247 continue; // should never happen
250 scale = DotProduct (delta, plane.normal);
251 scale *= -DotProduct (delta, patch2->plane->normal);
255 // check exact tramsfer
256 if (TestLine_r (0, patch->origin, patch2->origin) )
259 trans = scale * patch2->area / (dist*dist);
262 trans = 0; // rounding errors...
264 transfers[j] = trans;
268 patch->numtransfers++;
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
277 if (patch->numtransfers)
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");
289 // normalize all transfers so all of the light
290 // is transfered to the surroundings
292 t = patch->transfers;
294 for (j=0 ; j<num_patches ; j++)
296 if (transfers[j] <= 0)
298 itrans = transfers[j]*0x10000 / total;
300 t->transfer = itrans;
306 // don't bother locking around this. not that important.
307 total_transfer += patch->numtransfers;
316 void FreeTransfers (void)
320 for (i=0 ; i<num_patches ; i++)
322 free (patches[i].transfers);
323 patches[i].transfers = NULL;
328 //===================================================================
335 void WriteWorld (char *name)
342 out = fopen (name, "w");
344 Error ("Couldn't open %s", name);
346 for (j=0, patch=patches ; j<num_patches ; j++, patch++)
349 fprintf (out, "%i\n", w->numpoints);
350 for (i=0 ; i<w->numpoints ; i++)
352 fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
356 patch->totallight[0],
357 patch->totallight[1],
358 patch->totallight[2]);
371 void WriteGlView (void)
379 strcpy (name, source);
380 StripExtension (name);
381 strcat (name, ".glr");
383 f = fopen (name, "w");
385 Error ("Couldn't open %s", f);
387 for (j=0 ; j<num_patches ; j++)
391 fprintf (f, "%i\n", w->numpoints);
392 for (i=0 ; i<w->numpoints ; i++)
394 fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
398 p->totallight[0]/128,
399 p->totallight[1]/128,
400 p->totallight[2]/128);
409 //==============================================================
416 float CollectLight (void)
424 for (i=0, patch=patches ; i<num_patches ; i++, patch++)
426 // skys never collect light, it is just dropped
429 VectorClear (radiosity[i]);
430 VectorClear (illumination[i]);
434 for (j=0 ; j<3 ; j++)
436 patch->totallight[j] += illumination[i][j] / patch->area;
437 radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
440 total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
441 VectorClear (illumination[i]);
452 Send light out to other patches
456 void ShootLight (int patchnum)
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];
471 trans = patch->transfers;
472 num = patch->numtransfers;
474 for (k=0 ; k<num ; k++, trans++)
476 for (l=0 ; l<3 ; l++)
477 illumination[trans->patch][l] += send[l]*trans->transfer;
486 void BounceLight (void)
493 for (i=0 ; i<num_patches ; i++)
496 for (j=0 ; j<3 ; j++)
498 // p->totallight[j] = p->samplelight[j];
499 radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
503 for (i=0 ; i<numbounce ; i++)
505 RunThreadsOnIndividual (num_patches, false, ShootLight);
506 added = CollectLight ();
508 Sys_FPrintf( SYS_VRB, "bounce:%i added:%f\n", i, added);
509 if ( dumppatches && (i==0 || i == numbounce-1) )
511 sprintf (name, "bounce%i.txt", i);
519 //==============================================================
521 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");
541 if (numnodes == 0 || numfaces == 0)
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);
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
577 // blend bounced light into direct light and save
582 RunThreadsOnIndividual (numfaces, true, FinalLightFace);
599 Sys_Printf ("\n----- RAD ----\n\n");
604 start = I_FloatTime ();
606 if ( !strcmp( game, "heretic2" ) )
607 CalcTextureReflectivity = &CalcTextureReflectivity_Heretic2;
609 CalcTextureReflectivity = &CalcTextureReflectivity_Quake2;
611 SetQdirFromPath (mapname);
612 strcpy (source, ExpandArg(mapname));
613 StripExtension (source);
614 DefaultExtension (source, ".bsp");
618 sprintf (name, "%s%s", inbase, source);
619 Sys_Printf ("reading %s\n", name);
622 (*CalcTextureReflectivity) ();
626 Sys_Printf ("No vis information, direct lighting only.\n");
633 sprintf (name, "%s%s", outbase, source);
634 Sys_Printf ("writing %s\n", name);
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 );