-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-// qrad.c\r
-\r
-#include "qrad.h"\r
-\r
-\r
-\r
-/*\r
-\r
-NOTES\r
------\r
-\r
-every surface must be divided into at least two patches each axis\r
-\r
-*/\r
-\r
-patch_t *face_patches[MAX_MAP_FACES];\r
-entity_t *face_entity[MAX_MAP_FACES];\r
-patch_t patches[MAX_PATCHES];\r
-unsigned num_patches;\r
-\r
-vec3_t radiosity[MAX_PATCHES]; // light leaving a patch\r
-vec3_t illumination[MAX_PATCHES]; // light arriving at a patch\r
-\r
-vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels\r
-dplane_t backplanes[MAX_MAP_PLANES];\r
-\r
-char inbase[32], outbase[32];\r
-\r
-int fakeplanes; // created planes for origin offset \r
-\r
-int numbounce = 8;\r
-qboolean extrasamples;\r
-\r
-float subdiv = 64;\r
-qboolean dumppatches;\r
-\r
-void BuildLightmaps (void);\r
-int TestLine (vec3_t start, vec3_t stop);\r
-\r
-int junk;\r
-\r
-float ambient = 0;\r
-float maxlight = 196;\r
-\r
-float lightscale = 1.0;\r
-\r
-qboolean glview;\r
-\r
-qboolean nopvs;\r
-\r
-char source[1024];\r
-\r
-float direct_scale = 0.4;\r
-float entity_scale = 1.0;\r
-\r
-/*\r
-===================================================================\r
-\r
-MISC\r
-\r
-===================================================================\r
-*/\r
-\r
-\r
-/*\r
-=============\r
-MakeBackplanes\r
-=============\r
-*/\r
-void MakeBackplanes (void)\r
-{\r
- int i;\r
-\r
- for (i=0 ; i<numplanes ; i++)\r
- {\r
- backplanes[i].dist = -dplanes[i].dist;\r
- VectorSubtract (vec3_origin, dplanes[i].normal, backplanes[i].normal);\r
- }\r
-}\r
-\r
-int leafparents[MAX_MAP_LEAFS];\r
-int nodeparents[MAX_MAP_NODES];\r
-\r
-/*\r
-=============\r
-MakeParents\r
-=============\r
-*/\r
-void MakeParents (int nodenum, int parent)\r
-{\r
- int i, j;\r
- dnode_t *node;\r
-\r
- nodeparents[nodenum] = parent;\r
- node = &dnodes[nodenum];\r
-\r
- for (i=0 ; i<2 ; i++)\r
- {\r
- j = node->children[i];\r
- if (j < 0)\r
- leafparents[-j - 1] = nodenum;\r
- else\r
- MakeParents (j, nodenum);\r
- }\r
-}\r
-\r
-\r
-/*\r
-===================================================================\r
-\r
-TRANSFER SCALES\r
-\r
-===================================================================\r
-*/\r
-\r
-int PointInLeafnum (vec3_t point)\r
-{\r
- int nodenum;\r
- vec_t dist;\r
- dnode_t *node;\r
- dplane_t *plane;\r
-\r
- nodenum = 0;\r
- while (nodenum >= 0)\r
- {\r
- node = &dnodes[nodenum];\r
- plane = &dplanes[node->planenum];\r
- dist = DotProduct (point, plane->normal) - plane->dist;\r
- if (dist > 0)\r
- nodenum = node->children[0];\r
- else\r
- nodenum = node->children[1];\r
- }\r
-\r
- return -nodenum - 1;\r
-}\r
-\r
-\r
-dleaf_t *Rad_PointInLeaf (vec3_t point)\r
-{\r
- int num;\r
-\r
- num = PointInLeafnum (point);\r
- return &dleafs[num];\r
-}\r
-\r
-\r
-qboolean PvsForOrigin (vec3_t org, byte *pvs)\r
-{\r
- dleaf_t *leaf;\r
-\r
- if (!visdatasize)\r
- {\r
- memset (pvs, 255, (numleafs+7)/8 );\r
- return true;\r
- }\r
-\r
- leaf = Rad_PointInLeaf (org);\r
- if (leaf->cluster == -1)\r
- return false; // in solid leaf\r
-\r
- DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs);\r
- return true;\r
-}\r
-\r
-\r
-/*\r
-=============\r
-MakeTransfers\r
-\r
-=============\r
-*/\r
-int total_transfer;\r
-\r
-void MakeTransfers (int i)\r
-{\r
- int j;\r
- vec3_t delta;\r
- vec_t dist, scale;\r
- float trans;\r
- int itrans;\r
- patch_t *patch, *patch2;\r
- float total;\r
- dplane_t plane;\r
- vec3_t origin;\r
- float transfers[MAX_PATCHES], *all_transfers;\r
- int s;\r
- int itotal;\r
- byte pvs[(MAX_MAP_LEAFS+7)/8];\r
- int cluster;\r
-\r
- patch = patches + i;\r
- total = 0;\r
-\r
- VectorCopy (patch->origin, origin);\r
- plane = *patch->plane;\r
-\r
- if (!PvsForOrigin (patch->origin, pvs))\r
- return;\r
-\r
- // find out which patch2s will collect light\r
- // from patch\r
-\r
- all_transfers = transfers;\r
- patch->numtransfers = 0;\r
- for (j=0, patch2 = patches ; j<num_patches ; j++, patch2++)\r
- {\r
- transfers[j] = 0;\r
-\r
- if (j == i)\r
- continue;\r
-\r
- // check pvs bit\r
- if (!nopvs)\r
- {\r
- cluster = patch2->cluster;\r
- if (cluster == -1)\r
- continue;\r
- if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) )\r
- continue; // not in pvs\r
- }\r
-\r
- // calculate vector\r
- VectorSubtract (patch2->origin, origin, delta);\r
- dist = VectorNormalize (delta, delta);\r
- if (!dist)\r
- continue; // should never happen\r
-\r
- // reletive angles\r
- scale = DotProduct (delta, plane.normal);\r
- scale *= -DotProduct (delta, patch2->plane->normal);\r
- if (scale <= 0)\r
- continue;\r
-\r
- // check exact tramsfer\r
- if (TestLine_r (0, patch->origin, patch2->origin) )\r
- continue;\r
-\r
- trans = scale * patch2->area / (dist*dist);\r
-\r
- if (trans < 0)\r
- trans = 0; // rounding errors...\r
-\r
- transfers[j] = trans;\r
- if (trans > 0)\r
- {\r
- total += trans;\r
- patch->numtransfers++;\r
- }\r
- }\r
-\r
- // copy the transfers out and normalize\r
- // total should be somewhere near PI if everything went right\r
- // because partial occlusion isn't accounted for, and nearby\r
- // patches have underestimated form factors, it will usually\r
- // be higher than PI\r
- if (patch->numtransfers)\r
- {\r
- transfer_t *t;\r
- \r
- if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES)\r
- Error ("Weird numtransfers");\r
- s = patch->numtransfers * sizeof(transfer_t);\r
- patch->transfers = malloc (s);\r
- if (!patch->transfers)\r
- Error ("Memory allocation failure");\r
-\r
- //\r
- // normalize all transfers so all of the light\r
- // is transfered to the surroundings\r
- //\r
- t = patch->transfers;\r
- itotal = 0;\r
- for (j=0 ; j<num_patches ; j++)\r
- {\r
- if (transfers[j] <= 0)\r
- continue;\r
- itrans = transfers[j]*0x10000 / total;\r
- itotal += itrans;\r
- t->transfer = itrans;\r
- t->patch = j;\r
- t++;\r
- }\r
- }\r
-\r
- // don't bother locking around this. not that important.\r
- total_transfer += patch->numtransfers;\r
-}\r
-\r
-\r
-/*\r
-=============\r
-FreeTransfers\r
-=============\r
-*/\r
-void FreeTransfers (void)\r
-{\r
- int i;\r
-\r
- for (i=0 ; i<num_patches ; i++)\r
- {\r
- free (patches[i].transfers);\r
- patches[i].transfers = NULL;\r
- }\r
-}\r
-\r
-\r
-//===================================================================\r
-\r
-/*\r
-=============\r
-WriteWorld\r
-=============\r
-*/\r
-void WriteWorld (char *name)\r
-{\r
- int i, j;\r
- FILE *out;\r
- patch_t *patch;\r
- winding_t *w;\r
-\r
- out = fopen (name, "w");\r
- if (!out)\r
- Error ("Couldn't open %s", name);\r
-\r
- for (j=0, patch=patches ; j<num_patches ; j++, patch++)\r
- {\r
- w = patch->winding;\r
- fprintf (out, "%i\n", w->numpoints);\r
- for (i=0 ; i<w->numpoints ; i++)\r
- {\r
- fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",\r
- w->p[i][0],\r
- w->p[i][1],\r
- w->p[i][2],\r
- patch->totallight[0],\r
- patch->totallight[1],\r
- patch->totallight[2]);\r
- }\r
- fprintf (out, "\n");\r
- }\r
-\r
- fclose (out);\r
-}\r
-\r
-/*\r
-=============\r
-WriteGlView\r
-=============\r
-*/\r
-void WriteGlView (void)\r
-{\r
- char name[1024];\r
- FILE *f;\r
- int i, j;\r
- patch_t *p;\r
- winding_t *w;\r
-\r
- strcpy (name, source);\r
- StripExtension (name);\r
- strcat (name, ".glr");\r
-\r
- f = fopen (name, "w");\r
- if (!f)\r
- Error ("Couldn't open %s", f);\r
-\r
- for (j=0 ; j<num_patches ; j++)\r
- {\r
- p = &patches[j];\r
- w = p->winding;\r
- fprintf (f, "%i\n", w->numpoints);\r
- for (i=0 ; i<w->numpoints ; i++)\r
- {\r
- fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",\r
- w->p[i][0],\r
- w->p[i][1],\r
- w->p[i][2],\r
- p->totallight[0]/128,\r
- p->totallight[1]/128,\r
- p->totallight[2]/128);\r
- }\r
- fprintf (f, "\n");\r
- }\r
-\r
- fclose (f);\r
-}\r
-\r
-\r
-//==============================================================\r
-\r
-/*\r
-=============\r
-CollectLight\r
-=============\r
-*/\r
-float CollectLight (void)\r
-{\r
- int i, j;\r
- patch_t *patch;\r
- vec_t total;\r
-\r
- total = 0;\r
-\r
- for (i=0, patch=patches ; i<num_patches ; i++, patch++)\r
- {\r
- // skys never collect light, it is just dropped\r
- if (patch->sky)\r
- {\r
- VectorClear (radiosity[i]);\r
- VectorClear (illumination[i]);\r
- continue;\r
- }\r
-\r
- for (j=0 ; j<3 ; j++)\r
- {\r
- patch->totallight[j] += illumination[i][j] / patch->area;\r
- radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];\r
- }\r
-\r
- total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];\r
- VectorClear (illumination[i]);\r
- }\r
-\r
- return total;\r
-}\r
-\r
-\r
-/*\r
-=============\r
-ShootLight\r
-\r
-Send light out to other patches\r
- Run multi-threaded\r
-=============\r
-*/\r
-void ShootLight (int patchnum)\r
-{\r
- int k, l;\r
- transfer_t *trans;\r
- int num;\r
- patch_t *patch;\r
- vec3_t send;\r
-\r
- // this is the amount of light we are distributing\r
- // prescale it so that multiplying by the 16 bit\r
- // transfer values gives a proper output value\r
- for (k=0 ; k<3 ; k++)\r
- send[k] = radiosity[patchnum][k] / 0x10000;\r
- patch = &patches[patchnum];\r
-\r
- trans = patch->transfers;\r
- num = patch->numtransfers;\r
-\r
- for (k=0 ; k<num ; k++, trans++)\r
- {\r
- for (l=0 ; l<3 ; l++)\r
- illumination[trans->patch][l] += send[l]*trans->transfer;\r
- }\r
-}\r
-\r
-/*\r
-=============\r
-BounceLight\r
-=============\r
-*/\r
-void BounceLight (void)\r
-{\r
- int i, j;\r
- float added;\r
- char name[64];\r
- patch_t *p;\r
-\r
- for (i=0 ; i<num_patches ; i++)\r
- {\r
- p = &patches[i];\r
- for (j=0 ; j<3 ; j++)\r
- {\r
-// p->totallight[j] = p->samplelight[j];\r
- radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;\r
- }\r
- }\r
-\r
- for (i=0 ; i<numbounce ; i++)\r
- {\r
- RunThreadsOnIndividual (num_patches, false, ShootLight);\r
- added = CollectLight ();\r
-\r
- Sys_FPrintf( SYS_VRB, "bounce:%i added:%f\n", i, added);\r
- if ( dumppatches && (i==0 || i == numbounce-1) )\r
- {\r
- sprintf (name, "bounce%i.txt", i);\r
- WriteWorld (name);\r
- }\r
- }\r
-}\r
-\r
-\r
-\r
-//==============================================================\r
-\r
-void CheckPatches (void)\r
-{\r
- int i;\r
- patch_t *patch;\r
-\r
- for (i=0 ; i<num_patches ; i++)\r
- {\r
- patch = &patches[i];\r
- if (patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0)\r
- Error ("negative patch totallight\n");\r
- }\r
-}\r
-\r
-/*\r
-=============\r
-RadWorld\r
-=============\r
-*/\r
-void RadWorld (void)\r
-{\r
- if (numnodes == 0 || numfaces == 0)\r
- Error ("Empty map");\r
- MakeBackplanes ();\r
- MakeParents (0, -1);\r
- MakeTnodes (&dmodels[0]);\r
-\r
- // turn each face into a single patch\r
- MakePatches ();\r
-\r
- // subdivide patches to a maximum dimension\r
- SubdividePatches ();\r
-\r
- // create directlights out of patches and lights\r
- CreateDirectLights ();\r
-\r
- // build initial facelights\r
- RunThreadsOnIndividual (numfaces, true, BuildFacelights);\r
-\r
- if (numbounce > 0)\r
- {\r
- // build transfer lists\r
- RunThreadsOnIndividual (num_patches, true, MakeTransfers);\r
- Sys_FPrintf( SYS_VRB, "transfer lists: %5.1f megs\n"\r
- , (float)total_transfer * sizeof(transfer_t) / (1024*1024));\r
-\r
- // spread light around\r
- BounceLight ();\r
- \r
- FreeTransfers ();\r
-\r
- CheckPatches ();\r
- }\r
-\r
- if (glview)\r
- WriteGlView ();\r
-\r
- // blend bounced light into direct light and save\r
- PairEdges ();\r
- LinkPlaneFaces ();\r
-\r
- lightdatasize = 0;\r
- RunThreadsOnIndividual (numfaces, true, FinalLightFace);\r
-}\r
-\r
-\r
-/*\r
-========\r
-main\r
-\r
-light modelfile\r
-========\r
-*/\r
-int RAD_Main ()\r
-{\r
- double start, end;\r
- char name[1024];\r
- int total_rad_time;\r
-\r
- Sys_Printf ("\n----- RAD ----\n\n");\r
-\r
- if (maxlight > 255)\r
- maxlight = 255;\r
-\r
- start = I_FloatTime ();\r
-\r
- if ( !strcmp( game, "heretic2" ) )\r
- CalcTextureReflectivity = &CalcTextureReflectivity_Heretic2;\r
- else\r
- CalcTextureReflectivity = &CalcTextureReflectivity_Quake2;\r
- \r
- SetQdirFromPath (mapname); \r
- strcpy (source, ExpandArg(mapname));\r
- StripExtension (source);\r
- DefaultExtension (source, ".bsp");\r
-\r
-// ReadLightFile ();\r
-\r
- sprintf (name, "%s%s", inbase, source);\r
- Sys_Printf ("reading %s\n", name);\r
- LoadBSPFile (name);\r
- ParseEntities ();\r
- (*CalcTextureReflectivity) ();\r
-\r
- if (!visdatasize)\r
- {\r
- Sys_Printf ("No vis information, direct lighting only.\n");\r
- numbounce = 0;\r
- ambient = 0.1;\r
- }\r
-\r
- RadWorld ();\r
-\r
- sprintf (name, "%s%s", outbase, source);\r
- Sys_Printf ("writing %s\n", name);\r
- WriteBSPFile (name);\r
-\r
- end = I_FloatTime ();\r
- total_rad_time = (int) (end-start);\r
- Sys_Printf("\nRAD Time: ");\r
- if ( total_rad_time > 59 )\r
- Sys_Printf("%d Minutes ", total_rad_time/60 );\r
- Sys_Printf( "%d Seconds\n", total_rad_time%60 );\r
- \r
- \r
- return 0;\r
-}\r
-\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+// qrad.c
+
+#include "qrad.h"
+
+
+
+/*
+
+NOTES
+-----
+
+every surface must be divided into at least two patches each axis
+
+*/
+
+patch_t *face_patches[MAX_MAP_FACES];
+entity_t *face_entity[MAX_MAP_FACES];
+patch_t patches[MAX_PATCHES];
+unsigned num_patches;
+
+vec3_t radiosity[MAX_PATCHES]; // light leaving a patch
+vec3_t illumination[MAX_PATCHES]; // light arriving at a patch
+
+vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels
+dplane_t backplanes[MAX_MAP_PLANES];
+
+char inbase[32], outbase[32];
+
+int fakeplanes; // created planes for origin offset
+
+int numbounce = 8;
+qboolean extrasamples;
+
+float subdiv = 64;
+qboolean dumppatches;
+
+void BuildLightmaps (void);
+int TestLine (vec3_t start, vec3_t stop);
+
+int junk;
+
+float ambient = 0;
+float maxlight = 196;
+
+float lightscale = 1.0;
+
+qboolean glview;
+
+qboolean nopvs;
+
+char source[1024];
+
+float direct_scale = 0.4;
+float entity_scale = 1.0;
+
+/*
+===================================================================
+
+MISC
+
+===================================================================
+*/
+
+
+/*
+=============
+MakeBackplanes
+=============
+*/
+void MakeBackplanes (void)
+{
+ int i;
+
+ for (i=0 ; i<numplanes ; i++)
+ {
+ backplanes[i].dist = -dplanes[i].dist;
+ VectorSubtract (vec3_origin, dplanes[i].normal, backplanes[i].normal);
+ }
+}
+
+int leafparents[MAX_MAP_LEAFS];
+int nodeparents[MAX_MAP_NODES];
+
+/*
+=============
+MakeParents
+=============
+*/
+void MakeParents (int nodenum, int parent)
+{
+ int i, j;
+ dnode_t *node;
+
+ nodeparents[nodenum] = parent;
+ node = &dnodes[nodenum];
+
+ for (i=0 ; i<2 ; i++)
+ {
+ j = node->children[i];
+ if (j < 0)
+ leafparents[-j - 1] = nodenum;
+ else
+ MakeParents (j, nodenum);
+ }
+}
+
+
+/*
+===================================================================
+
+TRANSFER SCALES
+
+===================================================================
+*/
+
+int PointInLeafnum (vec3_t point)
+{
+ int nodenum;
+ vec_t dist;
+ dnode_t *node;
+ dplane_t *plane;
+
+ nodenum = 0;
+ while (nodenum >= 0)
+ {
+ node = &dnodes[nodenum];
+ plane = &dplanes[node->planenum];
+ dist = DotProduct (point, plane->normal) - plane->dist;
+ if (dist > 0)
+ nodenum = node->children[0];
+ else
+ nodenum = node->children[1];
+ }
+
+ return -nodenum - 1;
+}
+
+
+dleaf_t *Rad_PointInLeaf (vec3_t point)
+{
+ int num;
+
+ num = PointInLeafnum (point);
+ return &dleafs[num];
+}
+
+
+qboolean PvsForOrigin (vec3_t org, byte *pvs)
+{
+ dleaf_t *leaf;
+
+ if (!visdatasize)
+ {
+ memset (pvs, 255, (numleafs+7)/8 );
+ return true;
+ }
+
+ leaf = Rad_PointInLeaf (org);
+ if (leaf->cluster == -1)
+ return false; // in solid leaf
+
+ DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs);
+ return true;
+}
+
+
+/*
+=============
+MakeTransfers
+
+=============
+*/
+int total_transfer;
+
+void MakeTransfers (int i)
+{
+ int j;
+ vec3_t delta;
+ vec_t dist, scale;
+ float trans;
+ int itrans;
+ patch_t *patch, *patch2;
+ float total;
+ dplane_t plane;
+ vec3_t origin;
+ float transfers[MAX_PATCHES], *all_transfers;
+ int s;
+ int itotal;
+ byte pvs[(MAX_MAP_LEAFS+7)/8];
+ int cluster;
+
+ patch = patches + i;
+ total = 0;
+
+ VectorCopy (patch->origin, origin);
+ plane = *patch->plane;
+
+ if (!PvsForOrigin (patch->origin, pvs))
+ return;
+
+ // find out which patch2s will collect light
+ // from patch
+
+ all_transfers = transfers;
+ patch->numtransfers = 0;
+ for (j=0, patch2 = patches ; j<num_patches ; j++, patch2++)
+ {
+ transfers[j] = 0;
+
+ if (j == i)
+ continue;
+
+ // check pvs bit
+ if (!nopvs)
+ {
+ cluster = patch2->cluster;
+ if (cluster == -1)
+ continue;
+ if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) )
+ continue; // not in pvs
+ }
+
+ // calculate vector
+ VectorSubtract (patch2->origin, origin, delta);
+ dist = VectorNormalize (delta, delta);
+ if (!dist)
+ continue; // should never happen
+
+ // reletive angles
+ scale = DotProduct (delta, plane.normal);
+ scale *= -DotProduct (delta, patch2->plane->normal);
+ if (scale <= 0)
+ continue;
+
+ // check exact tramsfer
+ if (TestLine_r (0, patch->origin, patch2->origin) )
+ continue;
+
+ trans = scale * patch2->area / (dist*dist);
+
+ if (trans < 0)
+ trans = 0; // rounding errors...
+
+ transfers[j] = trans;
+ if (trans > 0)
+ {
+ total += trans;
+ patch->numtransfers++;
+ }
+ }
+
+ // copy the transfers out and normalize
+ // total should be somewhere near PI if everything went right
+ // because partial occlusion isn't accounted for, and nearby
+ // patches have underestimated form factors, it will usually
+ // be higher than PI
+ if (patch->numtransfers)
+ {
+ transfer_t *t;
+
+ if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES)
+ Error ("Weird numtransfers");
+ s = patch->numtransfers * sizeof(transfer_t);
+ patch->transfers = malloc (s);
+ if (!patch->transfers)
+ Error ("Memory allocation failure");
+
+ //
+ // normalize all transfers so all of the light
+ // is transfered to the surroundings
+ //
+ t = patch->transfers;
+ itotal = 0;
+ for (j=0 ; j<num_patches ; j++)
+ {
+ if (transfers[j] <= 0)
+ continue;
+ itrans = transfers[j]*0x10000 / total;
+ itotal += itrans;
+ t->transfer = itrans;
+ t->patch = j;
+ t++;
+ }
+ }
+
+ // don't bother locking around this. not that important.
+ total_transfer += patch->numtransfers;
+}
+
+
+/*
+=============
+FreeTransfers
+=============
+*/
+void FreeTransfers (void)
+{
+ int i;
+
+ for (i=0 ; i<num_patches ; i++)
+ {
+ free (patches[i].transfers);
+ patches[i].transfers = NULL;
+ }
+}
+
+
+//===================================================================
+
+/*
+=============
+WriteWorld
+=============
+*/
+void WriteWorld (char *name)
+{
+ int i, j;
+ FILE *out;
+ patch_t *patch;
+ winding_t *w;
+
+ out = fopen (name, "w");
+ if (!out)
+ Error ("Couldn't open %s", name);
+
+ for (j=0, patch=patches ; j<num_patches ; j++, patch++)
+ {
+ w = patch->winding;
+ fprintf (out, "%i\n", w->numpoints);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
+ w->p[i][0],
+ w->p[i][1],
+ w->p[i][2],
+ patch->totallight[0],
+ patch->totallight[1],
+ patch->totallight[2]);
+ }
+ fprintf (out, "\n");
+ }
+
+ fclose (out);
+}
+
+/*
+=============
+WriteGlView
+=============
+*/
+void WriteGlView (void)
+{
+ char name[1024];
+ FILE *f;
+ int i, j;
+ patch_t *p;
+ winding_t *w;
+
+ strcpy (name, source);
+ StripExtension (name);
+ strcat (name, ".glr");
+
+ f = fopen (name, "w");
+ if (!f)
+ Error ("Couldn't open %s", f);
+
+ for (j=0 ; j<num_patches ; j++)
+ {
+ p = &patches[j];
+ w = p->winding;
+ fprintf (f, "%i\n", w->numpoints);
+ for (i=0 ; i<w->numpoints ; i++)
+ {
+ fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
+ w->p[i][0],
+ w->p[i][1],
+ w->p[i][2],
+ p->totallight[0]/128,
+ p->totallight[1]/128,
+ p->totallight[2]/128);
+ }
+ fprintf (f, "\n");
+ }
+
+ fclose (f);
+}
+
+
+//==============================================================
+
+/*
+=============
+CollectLight
+=============
+*/
+float CollectLight (void)
+{
+ int i, j;
+ patch_t *patch;
+ vec_t total;
+
+ total = 0;
+
+ for (i=0, patch=patches ; i<num_patches ; i++, patch++)
+ {
+ // skys never collect light, it is just dropped
+ if (patch->sky)
+ {
+ VectorClear (radiosity[i]);
+ VectorClear (illumination[i]);
+ continue;
+ }
+
+ for (j=0 ; j<3 ; j++)
+ {
+ patch->totallight[j] += illumination[i][j] / patch->area;
+ radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
+ }
+
+ total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
+ VectorClear (illumination[i]);
+ }
+
+ return total;
+}
+
+
+/*
+=============
+ShootLight
+
+Send light out to other patches
+ Run multi-threaded
+=============
+*/
+void ShootLight (int patchnum)
+{
+ int k, l;
+ transfer_t *trans;
+ int num;
+ patch_t *patch;
+ vec3_t send;
+
+ // this is the amount of light we are distributing
+ // prescale it so that multiplying by the 16 bit
+ // transfer values gives a proper output value
+ for (k=0 ; k<3 ; k++)
+ send[k] = radiosity[patchnum][k] / 0x10000;
+ patch = &patches[patchnum];
+
+ trans = patch->transfers;
+ num = patch->numtransfers;
+
+ for (k=0 ; k<num ; k++, trans++)
+ {
+ for (l=0 ; l<3 ; l++)
+ illumination[trans->patch][l] += send[l]*trans->transfer;
+ }
+}
+
+/*
+=============
+BounceLight
+=============
+*/
+void BounceLight (void)
+{
+ int i, j;
+ float added;
+ char name[64];
+ patch_t *p;
+
+ for (i=0 ; i<num_patches ; i++)
+ {
+ p = &patches[i];
+ for (j=0 ; j<3 ; j++)
+ {
+// p->totallight[j] = p->samplelight[j];
+ radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
+ }
+ }
+
+ for (i=0 ; i<numbounce ; i++)
+ {
+ RunThreadsOnIndividual (num_patches, false, ShootLight);
+ added = CollectLight ();
+
+ Sys_FPrintf( SYS_VRB, "bounce:%i added:%f\n", i, added);
+ if ( dumppatches && (i==0 || i == numbounce-1) )
+ {
+ sprintf (name, "bounce%i.txt", i);
+ WriteWorld (name);
+ }
+ }
+}
+
+
+
+//==============================================================
+
+void CheckPatches (void)
+{
+ int i;
+ patch_t *patch;
+
+ for (i=0 ; i<num_patches ; i++)
+ {
+ patch = &patches[i];
+ if (patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0)
+ Error ("negative patch totallight\n");
+ }
+}
+
+/*
+=============
+RadWorld
+=============
+*/
+void RadWorld (void)
+{
+ if (numnodes == 0 || numfaces == 0)
+ Error ("Empty map");
+ MakeBackplanes ();
+ MakeParents (0, -1);
+ MakeTnodes (&dmodels[0]);
+
+ // turn each face into a single patch
+ MakePatches ();
+
+ // subdivide patches to a maximum dimension
+ SubdividePatches ();
+
+ // create directlights out of patches and lights
+ CreateDirectLights ();
+
+ // build initial facelights
+ RunThreadsOnIndividual (numfaces, true, BuildFacelights);
+
+ if (numbounce > 0)
+ {
+ // build transfer lists
+ RunThreadsOnIndividual (num_patches, true, MakeTransfers);
+ Sys_FPrintf( SYS_VRB, "transfer lists: %5.1f megs\n"
+ , (float)total_transfer * sizeof(transfer_t) / (1024*1024));
+
+ // spread light around
+ BounceLight ();
+
+ FreeTransfers ();
+
+ CheckPatches ();
+ }
+
+ if (glview)
+ WriteGlView ();
+
+ // blend bounced light into direct light and save
+ PairEdges ();
+ LinkPlaneFaces ();
+
+ lightdatasize = 0;
+ RunThreadsOnIndividual (numfaces, true, FinalLightFace);
+}
+
+
+/*
+========
+main
+
+light modelfile
+========
+*/
+int RAD_Main ()
+{
+ double start, end;
+ char name[1024];
+ int total_rad_time;
+
+ Sys_Printf ("\n----- RAD ----\n\n");
+
+ if (maxlight > 255)
+ maxlight = 255;
+
+ start = I_FloatTime ();
+
+ if ( !strcmp( game, "heretic2" ) )
+ CalcTextureReflectivity = &CalcTextureReflectivity_Heretic2;
+ else
+ CalcTextureReflectivity = &CalcTextureReflectivity_Quake2;
+
+ SetQdirFromPath (mapname);
+ strcpy (source, ExpandArg(mapname));
+ StripExtension (source);
+ DefaultExtension (source, ".bsp");
+
+// ReadLightFile ();
+
+ sprintf (name, "%s%s", inbase, source);
+ Sys_Printf ("reading %s\n", name);
+ LoadBSPFile (name);
+ ParseEntities ();
+ (*CalcTextureReflectivity) ();
+
+ if (!visdatasize)
+ {
+ Sys_Printf ("No vis information, direct lighting only.\n");
+ numbounce = 0;
+ ambient = 0.1;
+ }
+
+ RadWorld ();
+
+ sprintf (name, "%s%s", outbase, source);
+ Sys_Printf ("writing %s\n", name);
+ WriteBSPFile (name);
+
+ end = I_FloatTime ();
+ total_rad_time = (int) (end-start);
+ Sys_Printf("\nRAD Time: ");
+ if ( total_rad_time > 59 )
+ Sys_Printf("%d Minutes ", total_rad_time/60 );
+ Sys_Printf( "%d Seconds\n", total_rad_time%60 );
+
+
+ return 0;
+}
+