PageRenderTime 27ms CodeModel.GetById 28ms RepoModel.GetById 1ms app.codeStats 0ms

/tools/quake2/extra/bsp/qrad3/qrad3.c

https://gitlab.com/viciious/netradiant
C | 717 lines | 455 code | 126 blank | 136 comment | 91 complexity | 4d6bf07cae1559b4aa8a0110c4e2d85d MD5 | raw file
  1. /*
  2. ===========================================================================
  3. Copyright (C) 1997-2006 Id Software, Inc.
  4. This file is part of Quake 2 Tools source code.
  5. Quake 2 Tools source code is free software; you can redistribute it
  6. and/or modify it under the terms of the GNU General Public License as
  7. published by the Free Software Foundation; either version 2 of the License,
  8. or (at your option) any later version.
  9. Quake 2 Tools source code is distributed in the hope that it will be
  10. useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with Quake 2 Tools source code; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  16. ===========================================================================
  17. */
  18. #include "qrad.h"
  19. /*
  20. NOTES
  21. -----
  22. every surface must be divided into at least two patches each axis
  23. */
  24. patch_t *face_patches[MAX_MAP_FACES];
  25. entity_t *face_entity[MAX_MAP_FACES];
  26. patch_t patches[MAX_PATCHES];
  27. unsigned num_patches;
  28. vec3_t radiosity[MAX_PATCHES]; // light leaving a patch
  29. vec3_t illumination[MAX_PATCHES]; // light arriving at a patch
  30. vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels
  31. dplane_t backplanes[MAX_MAP_PLANES];
  32. char inbase[32], outbase[32];
  33. int fakeplanes; // created planes for origin offset
  34. int numbounce = 8;
  35. qboolean extrasamples;
  36. float subdiv = 64;
  37. qboolean dumppatches;
  38. void BuildLightmaps (void);
  39. int TestLine (vec3_t start, vec3_t stop);
  40. int junk;
  41. float ambient = 0;
  42. float maxlight = 196;
  43. float lightscale = 1.0;
  44. qboolean glview;
  45. qboolean nopvs;
  46. char source[1024];
  47. float direct_scale = 0.4;
  48. float entity_scale = 1.0;
  49. /*
  50. ===================================================================
  51. MISC
  52. ===================================================================
  53. */
  54. /*
  55. =============
  56. MakeBackplanes
  57. =============
  58. */
  59. void MakeBackplanes (void)
  60. {
  61. int i;
  62. for (i=0 ; i<numplanes ; i++)
  63. {
  64. backplanes[i].dist = -dplanes[i].dist;
  65. VectorSubtract (vec3_origin, dplanes[i].normal, backplanes[i].normal);
  66. }
  67. }
  68. int leafparents[MAX_MAP_LEAFS];
  69. int nodeparents[MAX_MAP_NODES];
  70. /*
  71. =============
  72. MakeParents
  73. =============
  74. */
  75. void MakeParents (int nodenum, int parent)
  76. {
  77. int i, j;
  78. dnode_t *node;
  79. nodeparents[nodenum] = parent;
  80. node = &dnodes[nodenum];
  81. for (i=0 ; i<2 ; i++)
  82. {
  83. j = node->children[i];
  84. if (j < 0)
  85. leafparents[-j - 1] = nodenum;
  86. else
  87. MakeParents (j, nodenum);
  88. }
  89. }
  90. /*
  91. ===================================================================
  92. TRANSFER SCALES
  93. ===================================================================
  94. */
  95. int PointInLeafnum (vec3_t point)
  96. {
  97. int nodenum;
  98. vec_t dist;
  99. dnode_t *node;
  100. dplane_t *plane;
  101. nodenum = 0;
  102. while (nodenum >= 0)
  103. {
  104. node = &dnodes[nodenum];
  105. plane = &dplanes[node->planenum];
  106. dist = DotProduct (point, plane->normal) - plane->dist;
  107. if (dist > 0)
  108. nodenum = node->children[0];
  109. else
  110. nodenum = node->children[1];
  111. }
  112. return -nodenum - 1;
  113. }
  114. dleaf_t *PointInLeaf (vec3_t point)
  115. {
  116. int num;
  117. num = PointInLeafnum (point);
  118. return &dleafs[num];
  119. }
  120. qboolean PvsForOrigin (vec3_t org, byte *pvs)
  121. {
  122. dleaf_t *leaf;
  123. if (!visdatasize)
  124. {
  125. memset (pvs, 255, (numleafs+7)/8 );
  126. return true;
  127. }
  128. leaf = PointInLeaf (org);
  129. if (leaf->cluster == -1)
  130. return false; // in solid leaf
  131. DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs);
  132. return true;
  133. }
  134. /*
  135. =============
  136. MakeTransfers
  137. =============
  138. */
  139. int total_transfer;
  140. void MakeTransfers (int i)
  141. {
  142. int j;
  143. vec3_t delta;
  144. vec_t dist, scale;
  145. float trans;
  146. int itrans;
  147. patch_t *patch, *patch2;
  148. float total;
  149. dplane_t plane;
  150. vec3_t origin;
  151. float transfers[MAX_PATCHES], *all_transfers;
  152. int s;
  153. int itotal;
  154. byte pvs[(MAX_MAP_LEAFS+7)/8];
  155. int cluster;
  156. patch = patches + i;
  157. total = 0;
  158. VectorCopy (patch->origin, origin);
  159. plane = *patch->plane;
  160. if (!PvsForOrigin (patch->origin, pvs))
  161. return;
  162. // find out which patch2s will collect light
  163. // from patch
  164. all_transfers = transfers;
  165. patch->numtransfers = 0;
  166. for (j=0, patch2 = patches ; j<num_patches ; j++, patch2++)
  167. {
  168. transfers[j] = 0;
  169. if (j == i)
  170. continue;
  171. // check pvs bit
  172. if (!nopvs)
  173. {
  174. cluster = patch2->cluster;
  175. if (cluster == -1)
  176. continue;
  177. if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) )
  178. continue; // not in pvs
  179. }
  180. // calculate vector
  181. VectorSubtract (patch2->origin, origin, delta);
  182. dist = VectorNormalize (delta, delta);
  183. if (!dist)
  184. continue; // should never happen
  185. // reletive angles
  186. scale = DotProduct (delta, plane.normal);
  187. scale *= -DotProduct (delta, patch2->plane->normal);
  188. if (scale <= 0)
  189. continue;
  190. // check exact tramsfer
  191. if (TestLine_r (0, patch->origin, patch2->origin) )
  192. continue;
  193. trans = scale * patch2->area / (dist*dist);
  194. if (trans < 0)
  195. trans = 0; // rounding errors...
  196. transfers[j] = trans;
  197. if (trans > 0)
  198. {
  199. total += trans;
  200. patch->numtransfers++;
  201. }
  202. }
  203. // copy the transfers out and normalize
  204. // total should be somewhere near PI if everything went right
  205. // because partial occlusion isn't accounted for, and nearby
  206. // patches have underestimated form factors, it will usually
  207. // be higher than PI
  208. if (patch->numtransfers)
  209. {
  210. transfer_t *t;
  211. if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES)
  212. Error ("Weird numtransfers");
  213. s = patch->numtransfers * sizeof(transfer_t);
  214. patch->transfers = malloc (s);
  215. if (!patch->transfers)
  216. Error ("Memory allocation failure");
  217. //
  218. // normalize all transfers so all of the light
  219. // is transfered to the surroundings
  220. //
  221. t = patch->transfers;
  222. itotal = 0;
  223. for (j=0 ; j<num_patches ; j++)
  224. {
  225. if (transfers[j] <= 0)
  226. continue;
  227. itrans = transfers[j]*0x10000 / total;
  228. itotal += itrans;
  229. t->transfer = itrans;
  230. t->patch = j;
  231. t++;
  232. }
  233. }
  234. // don't bother locking around this. not that important.
  235. total_transfer += patch->numtransfers;
  236. }
  237. /*
  238. =============
  239. FreeTransfers
  240. =============
  241. */
  242. void FreeTransfers (void)
  243. {
  244. int i;
  245. for (i=0 ; i<num_patches ; i++)
  246. {
  247. free (patches[i].transfers);
  248. patches[i].transfers = NULL;
  249. }
  250. }
  251. //===================================================================
  252. /*
  253. =============
  254. WriteWorld
  255. =============
  256. */
  257. void WriteWorld (char *name)
  258. {
  259. int i, j;
  260. FILE *out;
  261. patch_t *patch;
  262. winding_t *w;
  263. out = fopen (name, "w");
  264. if (!out)
  265. Error ("Couldn't open %s", name);
  266. for (j=0, patch=patches ; j<num_patches ; j++, patch++)
  267. {
  268. w = patch->winding;
  269. fprintf (out, "%i\n", w->numpoints);
  270. for (i=0 ; i<w->numpoints ; i++)
  271. {
  272. fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
  273. w->p[i][0],
  274. w->p[i][1],
  275. w->p[i][2],
  276. patch->totallight[0],
  277. patch->totallight[1],
  278. patch->totallight[2]);
  279. }
  280. fprintf (out, "\n");
  281. }
  282. fclose (out);
  283. }
  284. /*
  285. =============
  286. WriteGlView
  287. =============
  288. */
  289. void WriteGlView (void)
  290. {
  291. char name[1024];
  292. FILE *f;
  293. int i, j;
  294. patch_t *p;
  295. winding_t *w;
  296. strcpy (name, source);
  297. StripExtension (name);
  298. strcat (name, ".glr");
  299. f = fopen (name, "w");
  300. if (!f)
  301. Error ("Couldn't open %s", f);
  302. for (j=0 ; j<num_patches ; j++)
  303. {
  304. p = &patches[j];
  305. w = p->winding;
  306. fprintf (f, "%i\n", w->numpoints);
  307. for (i=0 ; i<w->numpoints ; i++)
  308. {
  309. fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n",
  310. w->p[i][0],
  311. w->p[i][1],
  312. w->p[i][2],
  313. p->totallight[0]/128,
  314. p->totallight[1]/128,
  315. p->totallight[2]/128);
  316. }
  317. fprintf (f, "\n");
  318. }
  319. fclose (f);
  320. }
  321. //==============================================================
  322. /*
  323. =============
  324. CollectLight
  325. =============
  326. */
  327. float CollectLight (void)
  328. {
  329. int i, j;
  330. patch_t *patch;
  331. vec_t total;
  332. total = 0;
  333. for (i=0, patch=patches ; i<num_patches ; i++, patch++)
  334. {
  335. // skys never collect light, it is just dropped
  336. if (patch->sky)
  337. {
  338. VectorClear (radiosity[i]);
  339. VectorClear (illumination[i]);
  340. continue;
  341. }
  342. for (j=0 ; j<3 ; j++)
  343. {
  344. patch->totallight[j] += illumination[i][j] / patch->area;
  345. radiosity[i][j] = illumination[i][j] * patch->reflectivity[j];
  346. }
  347. total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2];
  348. VectorClear (illumination[i]);
  349. }
  350. return total;
  351. }
  352. /*
  353. =============
  354. ShootLight
  355. Send light out to other patches
  356. Run multi-threaded
  357. =============
  358. */
  359. void ShootLight (int patchnum)
  360. {
  361. int k, l;
  362. transfer_t *trans;
  363. int num;
  364. patch_t *patch;
  365. vec3_t send;
  366. // this is the amount of light we are distributing
  367. // prescale it so that multiplying by the 16 bit
  368. // transfer values gives a proper output value
  369. for (k=0 ; k<3 ; k++)
  370. send[k] = radiosity[patchnum][k] / 0x10000;
  371. patch = &patches[patchnum];
  372. trans = patch->transfers;
  373. num = patch->numtransfers;
  374. for (k=0 ; k<num ; k++, trans++)
  375. {
  376. for (l=0 ; l<3 ; l++)
  377. illumination[trans->patch][l] += send[l]*trans->transfer;
  378. }
  379. }
  380. /*
  381. =============
  382. BounceLight
  383. =============
  384. */
  385. void BounceLight (void)
  386. {
  387. int i, j;
  388. float added;
  389. char name[64];
  390. patch_t *p;
  391. for (i=0 ; i<num_patches ; i++)
  392. {
  393. p = &patches[i];
  394. for (j=0 ; j<3 ; j++)
  395. {
  396. // p->totallight[j] = p->samplelight[j];
  397. radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area;
  398. }
  399. }
  400. for (i=0 ; i<numbounce ; i++)
  401. {
  402. RunThreadsOnIndividual (num_patches, false, ShootLight);
  403. added = CollectLight ();
  404. qprintf ("bounce:%i added:%f\n", i, added);
  405. if ( dumppatches && (i==0 || i == numbounce-1) )
  406. {
  407. sprintf (name, "bounce%i.txt", i);
  408. WriteWorld (name);
  409. }
  410. }
  411. }
  412. //==============================================================
  413. void CheckPatches (void)
  414. {
  415. int i;
  416. patch_t *patch;
  417. for (i=0 ; i<num_patches ; i++)
  418. {
  419. patch = &patches[i];
  420. if (patch->totallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0)
  421. Error ("negative patch totallight\n");
  422. }
  423. }
  424. /*
  425. =============
  426. RadWorld
  427. =============
  428. */
  429. void RadWorld (void)
  430. {
  431. if (numnodes == 0 || numfaces == 0)
  432. Error ("Empty map");
  433. MakeBackplanes ();
  434. MakeParents (0, -1);
  435. MakeTnodes (&dmodels[0]);
  436. // turn each face into a single patch
  437. MakePatches ();
  438. // subdivide patches to a maximum dimension
  439. SubdividePatches ();
  440. // create directlights out of patches and lights
  441. CreateDirectLights ();
  442. // build initial facelights
  443. RunThreadsOnIndividual (numfaces, true, BuildFacelights);
  444. if (numbounce > 0)
  445. {
  446. // build transfer lists
  447. RunThreadsOnIndividual (num_patches, true, MakeTransfers);
  448. qprintf ("transfer lists: %5.1f megs\n"
  449. , (float)total_transfer * sizeof(transfer_t) / (1024*1024));
  450. // spread light around
  451. BounceLight ();
  452. FreeTransfers ();
  453. CheckPatches ();
  454. }
  455. if (glview)
  456. WriteGlView ();
  457. // blend bounced light into direct light and save
  458. PairEdges ();
  459. LinkPlaneFaces ();
  460. lightdatasize = 0;
  461. RunThreadsOnIndividual (numfaces, true, FinalLightFace);
  462. }
  463. /*
  464. ========
  465. main
  466. light modelfile
  467. ========
  468. */
  469. int main (int argc, char **argv)
  470. {
  471. int i;
  472. double start, end;
  473. char name[1024];
  474. printf ("----- Radiosity ----\n");
  475. verbose = false;
  476. for (i=1 ; i<argc ; i++)
  477. {
  478. if (!strcmp(argv[i],"-dump"))
  479. dumppatches = true;
  480. else if (!strcmp(argv[i],"-bounce"))
  481. {
  482. numbounce = atoi (argv[i+1]);
  483. i++;
  484. }
  485. else if (!strcmp(argv[i],"-v"))
  486. {
  487. verbose = true;
  488. }
  489. else if (!strcmp(argv[i],"-extra"))
  490. {
  491. extrasamples = true;
  492. printf ("extrasamples = true\n");
  493. }
  494. else if (!strcmp(argv[i],"-threads"))
  495. {
  496. numthreads = atoi (argv[i+1]);
  497. i++;
  498. }
  499. else if (!strcmp(argv[i],"-chop"))
  500. {
  501. subdiv = atoi (argv[i+1]);
  502. i++;
  503. }
  504. else if (!strcmp(argv[i],"-scale"))
  505. {
  506. lightscale = atof (argv[i+1]);
  507. i++;
  508. }
  509. else if (!strcmp(argv[i],"-direct"))
  510. {
  511. direct_scale *= atof(argv[i+1]);
  512. printf ("direct light scaling at %f\n", direct_scale);
  513. i++;
  514. }
  515. else if (!strcmp(argv[i],"-entity"))
  516. {
  517. entity_scale *= atof(argv[i+1]);
  518. printf ("entity light scaling at %f\n", entity_scale);
  519. i++;
  520. }
  521. else if (!strcmp(argv[i],"-glview"))
  522. {
  523. glview = true;
  524. printf ("glview = true\n");
  525. }
  526. else if (!strcmp(argv[i],"-nopvs"))
  527. {
  528. nopvs = true;
  529. printf ("nopvs = true\n");
  530. }
  531. else if (!strcmp(argv[i],"-ambient"))
  532. {
  533. ambient = atof (argv[i+1]) * 128;
  534. i++;
  535. }
  536. else if (!strcmp(argv[i],"-maxlight"))
  537. {
  538. maxlight = atof (argv[i+1]) * 128;
  539. i++;
  540. }
  541. else if (!strcmp (argv[i],"-tmpin"))
  542. strcpy (inbase, "/tmp");
  543. else if (!strcmp (argv[i],"-tmpout"))
  544. strcpy (outbase, "/tmp");
  545. else
  546. break;
  547. }
  548. ThreadSetDefault ();
  549. if (maxlight > 255)
  550. maxlight = 255;
  551. if (i != argc - 1)
  552. Error ("usage: qrad [-v] [-chop num] [-scale num] [-ambient num] [-maxlight num] [-threads num] bspfile");
  553. start = I_FloatTime ();
  554. SetQdirFromPath (argv[i]);
  555. strcpy (source, ExpandArg(argv[i]));
  556. StripExtension (source);
  557. DefaultExtension (source, ".bsp");
  558. // ReadLightFile ();
  559. sprintf (name, "%s%s", inbase, source);
  560. printf ("reading %s\n", name);
  561. LoadBSPFile (name);
  562. ParseEntities ();
  563. CalcTextureReflectivity ();
  564. if (!visdatasize)
  565. {
  566. printf ("No vis information, direct lighting only.\n");
  567. numbounce = 0;
  568. ambient = 0.1;
  569. }
  570. RadWorld ();
  571. sprintf (name, "%s%s", outbase, source);
  572. printf ("writing %s\n", name);
  573. WriteBSPFile (name);
  574. end = I_FloatTime ();
  575. printf ("%5.0f seconds elapsed\n", end-start);
  576. return 0;
  577. }