]> de.git.xonotic.org Git - voretournament/voretournament.git/blobdiff - misc/mediasource/extra/netradiant-src/tools/quake2/q2map/qrad.c
Include netRadiant source in this GIT
[voretournament/voretournament.git] / misc / mediasource / extra / netradiant-src / tools / quake2 / q2map / qrad.c
diff --git a/misc/mediasource/extra/netradiant-src/tools/quake2/q2map/qrad.c b/misc/mediasource/extra/netradiant-src/tools/quake2/q2map/qrad.c
new file mode 100644 (file)
index 0000000..e1744cd
--- /dev/null
@@ -0,0 +1,647 @@
+/*
+Copyright (C) 1999-2006 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;
+}
+