qcsg.cpp 54 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862
  1. /*
  2. CONSTRUCTIVE SOLID GEOMETRY -aka- C S G
  3. Code based on original code from Valve Software,
  4. Modified by Sean "Zoner" Cavanaugh ([email protected]) with permission.
  5. Modified by Tony "Merl" Moore ([email protected]) [AJM]
  6. */
  7. #ifdef SYSTEM_WIN32
  8. #pragma warning(disable:4996)
  9. #endif
  10. #pragma warning(disable:4018) // '<' : signed/unsigned mismatch
  11. #include "csg.h"
  12. /*
  13. NOTES
  14. - check map size for +/- 4k limit at load time
  15. - allow for multiple wad.cfg configurations per compile
  16. */
  17. static FILE* out[NUM_HULLS]; // pointer to each of the hull out files (.p0, .p1, ect.)
  18. static int c_tiny;
  19. static int c_tiny_clip;
  20. static int c_outfaces;
  21. static int c_csgfaces;
  22. BoundingBox world_bounds;
  23. #ifdef HLCSG_WADCFG
  24. char wadconfigname[MAX_WAD_CFG_NAME];
  25. #endif
  26. vec_t g_tiny_threshold = DEFAULT_TINY_THRESHOLD;
  27. bool g_noclip = DEFAULT_NOCLIP; // no clipping hull "-noclip"
  28. bool g_onlyents = DEFAULT_ONLYENTS; // onlyents mode "-onlyents"
  29. bool g_wadtextures = DEFAULT_WADTEXTURES; // "-nowadtextures"
  30. bool g_chart = DEFAULT_CHART; // show chart "-chart"
  31. bool g_skyclip = DEFAULT_SKYCLIP; // no sky clipping "-noskyclip"
  32. bool g_estimate = DEFAULT_ESTIMATE; // progress estimates "-estimate"
  33. bool g_info = DEFAULT_INFO; // "-info" ?
  34. const char* g_hullfile = NULL; // external hullfile "-hullfie sdfsd"
  35. #ifdef ZHLT_NULLTEX // AJM
  36. bool g_bUseNullTex = DEFAULT_NULLTEX; // "-nonulltex"
  37. #endif
  38. #ifdef HLCSG_PRECISIONCLIP // KGP
  39. cliptype g_cliptype = DEFAULT_CLIPTYPE; // "-cliptype <value>"
  40. #endif
  41. #ifdef HLCSG_NULLIFY_INVISIBLE
  42. const char* g_nullfile = NULL;
  43. #endif
  44. #ifdef HLCSG_CLIPECONOMY // AJM
  45. bool g_bClipNazi = DEFAULT_CLIPNAZI; // "-noclipeconomy"
  46. #endif
  47. #ifdef HLCSG_AUTOWAD // AJM
  48. bool g_bWadAutoDetect = DEFAULT_WADAUTODETECT; // "-wadautodetect"
  49. #endif
  50. #ifdef ZHLT_DETAIL // AJM
  51. bool g_bDetailBrushes = DEFAULT_DETAIL; // "-detail"
  52. #endif
  53. #ifdef ZHLT_PROGRESSFILE // AJM
  54. char* g_progressfile = DEFAULT_PROGRESSFILE; // "-progressfile path"
  55. #endif
  56. #ifdef ZHLT_INFO_COMPILE_PARAMETERS
  57. // =====================================================================================
  58. // GetParamsFromEnt
  59. // parses entity keyvalues for setting information
  60. // =====================================================================================
  61. void GetParamsFromEnt(entity_t* mapent)
  62. {
  63. int iTmp;
  64. char szTmp[256];
  65. Log("\nCompile Settings detected from info_compile_parameters entity\n");
  66. // verbose(choices) : "Verbose compile messages" : 0 = [ 0 : "Off" 1 : "On" ]
  67. iTmp = IntForKey(mapent, "verbose");
  68. if (iTmp == 1)
  69. {
  70. g_verbose = true;
  71. }
  72. else if (iTmp == 0)
  73. {
  74. g_verbose = false;
  75. }
  76. Log("%30s [ %-9s ]\n", "Compile Option", "setting");
  77. Log("%30s [ %-9s ]\n", "Verbose Compile Messages", g_verbose ? "on" : "off");
  78. // estimate(choices) :"Estimate Compile Times?" : 0 = [ 0: "Yes" 1: "No" ]
  79. if (IntForKey(mapent, "estimate"))
  80. {
  81. g_estimate = true;
  82. }
  83. else
  84. {
  85. g_estimate = false;
  86. }
  87. Log("%30s [ %-9s ]\n", "Estimate Compile Times", g_estimate ? "on" : "off");
  88. // priority(choices) : "Priority Level" : 0 = [ 0 : "Normal" 1 : "High" -1 : "Low" ]
  89. if (!strcmp(ValueForKey(mapent, "priority"), "1"))
  90. {
  91. g_threadpriority = eThreadPriorityHigh;
  92. Log("%30s [ %-9s ]\n", "Thread Priority", "high");
  93. }
  94. else if (!strcmp(ValueForKey(mapent, "priority"), "-1"))
  95. {
  96. g_threadpriority = eThreadPriorityLow;
  97. Log("%30s [ %-9s ]\n", "Thread Priority", "low");
  98. }
  99. // texdata(string) : "Texture Data Memory" : "4096"
  100. iTmp = IntForKey(mapent, "texdata") * 1024;
  101. if (iTmp > g_max_map_miptex)
  102. {
  103. g_max_map_miptex = iTmp;
  104. }
  105. sprintf_s(szTmp, "%i", g_max_map_miptex);
  106. Log("%30s [ %-9s ]\n", "Texture Data Memory", szTmp);
  107. // hullfile(string) : "Custom Hullfile"
  108. if (ValueForKey(mapent, "hullfile"))
  109. {
  110. g_hullfile = ValueForKey(mapent, "hullfile");
  111. Log("%30s [ %-9s ]\n", "Custom Hullfile", g_hullfile);
  112. }
  113. #ifdef HLCSG_AUTOWAD
  114. // wadautodetect(choices) : "Wad Auto Detect" : 0 = [ 0 : "Off" 1 : "On" ]
  115. if (!strcmp(ValueForKey(mapent, "wadautodetect"), "1"))
  116. {
  117. g_bWadAutoDetect = true;
  118. }
  119. else
  120. {
  121. g_bWadAutoDetect = false;
  122. }
  123. Log("%30s [ %-9s ]\n", "Wad Auto Detect", g_bWadAutoDetect ? "on" : "off");
  124. #endif
  125. #ifdef HLCSG_WADCFG
  126. // wadconfig(string) : "Custom Wad Configuration" : ""
  127. if (strlen(ValueForKey(mapent, "wadconfig")) > 0)
  128. {
  129. safe_strncpy(wadconfigname, ValueForKey(mapent, "wadconfig"), MAX_WAD_CFG_NAME);
  130. Log("%30s [ %-9s ]\n", "Custom Wad Configuration", wadconfigname);
  131. }
  132. #endif
  133. #ifdef HLCSG_CLIPECONOMY
  134. // noclipeconomy(choices) : "Strip Uneeded Clipnodes?" : 1 = [ 1 : "Yes" 0 : "No" ]
  135. iTmp = IntForKey(mapent, "noclipeconomy");
  136. if (iTmp == 1)
  137. {
  138. g_bClipNazi = true;
  139. }
  140. else if (iTmp == 0)
  141. {
  142. g_bClipNazi = false;
  143. }
  144. Log("%30s [ %-9s ]\n", "Clipnode Economy Mode", g_bClipNazi ? "on" : "off");
  145. #endif
  146. /*
  147. hlcsg(choices) : "HLCSG" : 1 =
  148. [
  149. 1 : "Normal"
  150. 2 : "Onlyents"
  151. 0 : "Off"
  152. ]
  153. */
  154. iTmp = IntForKey(mapent, "hlcsg");
  155. g_onlyents = false;
  156. if (iTmp == 2)
  157. {
  158. g_onlyents = true;
  159. }
  160. else if (iTmp == 0)
  161. {
  162. Fatal(assume_TOOL_CANCEL,
  163. "%s was set to \"Off\" (0) in info_compile_parameters entity, execution cancelled", g_Program);
  164. CheckFatal();
  165. }
  166. Log("%30s [ %-9s ]\n", "Onlyents", g_onlyents ? "on" : "off");
  167. /*
  168. nocliphull(choices) : "Generate clipping hulls" : 0 =
  169. [
  170. 0 : "Yes"
  171. 1 : "No"
  172. ]
  173. */
  174. iTmp = IntForKey(mapent, "nocliphull");
  175. if (iTmp == 1)
  176. {
  177. g_noclip = true;
  178. }
  179. else
  180. {
  181. g_noclip = false;
  182. }
  183. Log("%30s [ %-9s ]\n", "Clipping Hull Generation", g_noclip ? "off" : "on");
  184. #ifdef HLCSG_PRECISIONCLIP
  185. // cliptype(choices) : "Clip Hull Type" : 4 = [ 0 : "Smallest" 1 : "Normalized" 2: "Simple" 3 : "Precise" 4 : "Legacy" ]
  186. iTmp = IntForKey(mapent, "cliptype");
  187. switch(iTmp)
  188. {
  189. case 0:
  190. g_cliptype = clip_smallest;
  191. break;
  192. case 1:
  193. g_cliptype = clip_normalized;
  194. break;
  195. case 2:
  196. g_cliptype = clip_simple;
  197. break;
  198. case 3:
  199. g_cliptype = clip_precise;
  200. break;
  201. default:
  202. g_cliptype = clip_legacy;
  203. break;
  204. }
  205. Log("%30s [ %-9s ]\n", "Clip Hull Type", GetClipTypeString(g_cliptype));
  206. #endif
  207. /*
  208. noskyclip(choices) : "No Sky Clip" : 0 =
  209. [
  210. 1 : "On"
  211. 0 : "Off"
  212. ]
  213. */
  214. iTmp = IntForKey(mapent, "noskyclip");
  215. if (iTmp == 1)
  216. {
  217. g_skyclip = false;
  218. }
  219. else
  220. {
  221. g_skyclip = true;
  222. }
  223. Log("%30s [ %-9s ]\n", "Sky brush clip generation", g_skyclip ? "on" : "off");
  224. ///////////////
  225. Log("\n");
  226. }
  227. #endif
  228. // =====================================================================================
  229. // FixBevelTextures
  230. // =====================================================================================
  231. void FixBevelTextures()
  232. {
  233. for(int counter = 0; counter < g_numtexinfo; counter++)
  234. {
  235. if(g_texinfo[counter].flags & TEX_BEVEL)
  236. { g_texinfo[counter].flags &= ~TEX_BEVEL; }
  237. }
  238. }
  239. // =====================================================================================
  240. // NewFaceFromFace
  241. // Duplicates the non point information of a face, used by SplitFace
  242. // =====================================================================================
  243. bface_t* NewFaceFromFace(const bface_t* const in)
  244. {
  245. bface_t* newf;
  246. newf = (bface_t*)Alloc(sizeof(bface_t));
  247. newf->contents = in->contents;
  248. newf->texinfo = in->texinfo;
  249. newf->planenum = in->planenum;
  250. newf->plane = in->plane;
  251. return newf;
  252. }
  253. // =====================================================================================
  254. // FreeFace
  255. // =====================================================================================
  256. void FreeFace(bface_t* f)
  257. {
  258. delete f->w;
  259. Free(f);
  260. }
  261. // =====================================================================================
  262. // ClipFace
  263. // Clips a faces by a plane, returning the fragment on the backside and adding any
  264. // fragment to the outside.
  265. // Faces exactly on the plane will stay inside unless overdrawn by later brush.
  266. // Frontside is the side of the plane that holds the outside list.
  267. // Precedence is necesary to handle overlapping coplanar faces.
  268. #define SPLIT_EPSILON 0.3
  269. // =====================================================================================
  270. static bface_t* ClipFace(bface_t* f, bface_t** outside, const int splitplane, const bool precedence)
  271. {
  272. bface_t* front; // clip face
  273. Winding* fw; // forward wind
  274. Winding* bw; // back wind
  275. plane_t* split; // plane to clip on
  276. // handle exact plane matches special
  277. if (f->planenum == (splitplane ^ 1))
  278. return f; // opposite side, so put on inside list
  279. if (f->planenum == splitplane) // coplanar
  280. {
  281. // this fragment will go to the inside, because
  282. // the earlier one was clipped to the outside
  283. if (precedence)
  284. return f;
  285. f->next = *outside;
  286. *outside = f;
  287. return NULL;
  288. }
  289. split = &g_mapplanes[splitplane];
  290. f->w->Clip(split->normal, split->dist, &fw, &bw);
  291. if (!fw)
  292. {
  293. delete bw;
  294. return f;
  295. }
  296. else if (!bw)
  297. {
  298. delete fw;
  299. f->next = *outside;
  300. *outside = f;
  301. return NULL;
  302. }
  303. else
  304. {
  305. delete f->w;
  306. front = NewFaceFromFace(f);
  307. front->w = fw;
  308. fw->getBounds(front->bounds);
  309. front->next = *outside;
  310. *outside = front;
  311. f->w = bw;
  312. bw->getBounds(f->bounds);
  313. return f;
  314. }
  315. }
  316. // =====================================================================================
  317. // WriteFace
  318. // =====================================================================================
  319. void WriteFace(const int hull, const bface_t* const f)
  320. {
  321. unsigned int i;
  322. Winding* w;
  323. ThreadLock();
  324. if (!hull)
  325. c_csgfaces++;
  326. // .p0 format
  327. w = f->w;
  328. // plane summary
  329. fprintf(out[hull], "%i %i %i %u\n", f->planenum, f->texinfo, f->contents, w->m_NumPoints);
  330. // for each of the points on the face
  331. for (i = 0; i < w->m_NumPoints; i++)
  332. {
  333. // write the co-ords
  334. fprintf(out[hull], "%5.2f %5.2f %5.2f\n", w->m_Points[i][0], w->m_Points[i][1], w->m_Points[i][2]);
  335. }
  336. // put in an extra line break
  337. fprintf(out[hull], "\n");
  338. ThreadUnlock();
  339. }
  340. // =====================================================================================
  341. // SaveOutside
  342. // The faces remaining on the outside list are final polygons. Write them to the
  343. // output file.
  344. // Passable contents (water, lava, etc) will generate a mirrored copy of the face
  345. // to be seen from the inside.
  346. // =====================================================================================
  347. static void SaveOutside(const brush_t* const b, const int hull, bface_t* outside, const int mirrorcontents)
  348. {
  349. bface_t* f;
  350. bface_t* f2;
  351. bface_t* next;
  352. int i;
  353. vec3_t temp;
  354. for (f = outside; f; f = next)
  355. {
  356. next = f->next;
  357. if (f->w->getArea() < g_tiny_threshold)
  358. {
  359. c_tiny++;
  360. Verbose("Entity %i, Brush %i: tiny fragment\n", b->entitynum, b->brushnum);
  361. continue;
  362. }
  363. // count unique faces
  364. if (!hull)
  365. {
  366. for (f2 = b->hulls[hull].faces; f2; f2 = f2->next)
  367. {
  368. if (f2->planenum == f->planenum)
  369. {
  370. if (!f2->used)
  371. {
  372. f2->used = true;
  373. c_outfaces++;
  374. }
  375. break;
  376. }
  377. }
  378. }
  379. WriteFace(hull, f);
  380. // if (mirrorcontents != CONTENTS_SOLID)
  381. {
  382. f->planenum ^= 1;
  383. f->plane = &g_mapplanes[f->planenum];
  384. f->contents = mirrorcontents;
  385. // swap point orders
  386. for (i = 0; i < f->w->m_NumPoints / 2; i++) // add points backwards
  387. {
  388. VectorCopy(f->w->m_Points[i], temp);
  389. VectorCopy(f->w->m_Points[f->w->m_NumPoints - 1 - i], f->w->m_Points[i]);
  390. VectorCopy(temp, f->w->m_Points[f->w->m_NumPoints - 1 - i]);
  391. }
  392. WriteFace(hull, f);
  393. }
  394. FreeFace(f);
  395. }
  396. }
  397. // =====================================================================================
  398. // CopyFace
  399. // =====================================================================================
  400. bface_t* CopyFace(const bface_t* const f)
  401. {
  402. bface_t* n;
  403. n = NewFaceFromFace(f);
  404. n->w = f->w->Copy();
  405. n->bounds = f->bounds;
  406. return n;
  407. }
  408. // =====================================================================================
  409. // CopyFaceList
  410. // =====================================================================================
  411. bface_t* CopyFaceList(bface_t* f)
  412. {
  413. bface_t* head;
  414. bface_t* n;
  415. if (f)
  416. {
  417. head = CopyFace(f);
  418. n = head;
  419. f = f->next;
  420. while (f)
  421. {
  422. n->next = CopyFace(f);
  423. n = n->next;
  424. f = f->next;
  425. }
  426. return head;
  427. }
  428. else
  429. {
  430. return NULL;
  431. }
  432. }
  433. // =====================================================================================
  434. // FreeFaceList
  435. // =====================================================================================
  436. void FreeFaceList(bface_t* f)
  437. {
  438. if (f)
  439. {
  440. if (f->next)
  441. {
  442. FreeFaceList(f->next);
  443. }
  444. FreeFace(f);
  445. }
  446. }
  447. // =====================================================================================
  448. // CopyFacesToOutside
  449. // Make a copy of all the faces of the brush, so they can be chewed up by other
  450. // brushes.
  451. // All of the faces start on the outside list.
  452. // As other brushes take bites out of the faces, the fragments are moved to the
  453. // inside list, so they can be freed when they are determined to be completely
  454. // enclosed in solid.
  455. // =====================================================================================
  456. static bface_t* CopyFacesToOutside(brushhull_t* bh)
  457. {
  458. bface_t* f;
  459. bface_t* newf;
  460. bface_t* outside;
  461. outside = NULL;
  462. for (f = bh->faces; f; f = f->next)
  463. {
  464. newf = CopyFace(f);
  465. newf->w->getBounds(newf->bounds);
  466. newf->next = outside;
  467. outside = newf;
  468. }
  469. return outside;
  470. }
  471. // =====================================================================================
  472. // CSGBrush
  473. // =====================================================================================
  474. static void CSGBrush(int brushnum)
  475. {
  476. int hull;
  477. brush_t* b1;
  478. brush_t* b2;
  479. brushhull_t* bh1;
  480. brushhull_t* bh2;
  481. int bn;
  482. bool overwrite;
  483. bface_t* f;
  484. bface_t* f2;
  485. bface_t* next;
  486. bface_t* fcopy;
  487. bface_t* outside;
  488. bface_t* oldoutside;
  489. entity_t* e;
  490. vec_t area;
  491. // get entity and brush info from the given brushnum that we can work with
  492. b1 = &g_mapbrushes[brushnum];
  493. e = &g_entities[b1->entitynum];
  494. // for each of the hulls
  495. for (hull = 0; hull < NUM_HULLS; hull++)
  496. {
  497. bh1 = &b1->hulls[hull];
  498. // set outside to a copy of the brush's faces
  499. outside = CopyFacesToOutside(bh1);
  500. overwrite = false;
  501. // for each brush in entity e
  502. for (bn = 0; bn < e->numbrushes; bn++)
  503. {
  504. // see if b2 needs to clip a chunk out of b1
  505. if (bn == brushnum)
  506. {
  507. overwrite = true; // later brushes now overwrite
  508. continue;
  509. }
  510. b2 = &g_mapbrushes[e->firstbrush + bn];
  511. bh2 = &b2->hulls[hull];
  512. if (!bh2->faces)
  513. continue; // brush isn't in this hull
  514. // check brush bounding box first
  515. // TODO: use boundingbox method instead
  516. if (bh1->bounds.testDisjoint(bh2->bounds))
  517. {
  518. continue;
  519. }
  520. // divide faces by the planes of the b2 to find which
  521. // fragments are inside
  522. f = outside;
  523. outside = NULL;
  524. for (; f; f = next)
  525. {
  526. next = f->next;
  527. // check face bounding box first
  528. if (bh2->bounds.testDisjoint(f->bounds))
  529. { // this face doesn't intersect brush2's bbox
  530. f->next = outside;
  531. outside = f;
  532. continue;
  533. }
  534. oldoutside = outside;
  535. fcopy = CopyFace(f); // save to avoid fake splits
  536. // throw pieces on the front sides of the planes
  537. // into the outside list, return the remains on the inside
  538. for (f2 = bh2->faces; f2 && f; f2 = f2->next)
  539. {
  540. f = ClipFace(f, &outside, f2->planenum, overwrite);
  541. }
  542. area = f ? f->w->getArea() : 0;
  543. if (f && area < g_tiny_threshold)
  544. {
  545. Verbose("Entity %i, Brush %i: tiny penetration\n", b1->entitynum, b1->brushnum);
  546. c_tiny_clip++;
  547. FreeFace(f);
  548. f = NULL;
  549. }
  550. if (f)
  551. {
  552. // there is one convex fragment of the original
  553. // face left inside brush2
  554. FreeFace(fcopy);
  555. if (b1->contents > b2->contents)
  556. { // inside a water brush
  557. f->contents = b2->contents;
  558. f->next = outside;
  559. outside = f;
  560. }
  561. else // inside a solid brush
  562. {
  563. FreeFace(f); // throw it away
  564. }
  565. }
  566. else
  567. { // the entire thing was on the outside, even
  568. // though the bounding boxes intersected,
  569. // which will never happen with axial planes
  570. // free the fragments chopped to the outside
  571. while (outside != oldoutside)
  572. {
  573. f2 = outside->next;
  574. FreeFace(outside);
  575. outside = f2;
  576. }
  577. // revert to the original face to avoid
  578. // unneeded false cuts
  579. fcopy->next = outside;
  580. outside = fcopy;
  581. }
  582. }
  583. }
  584. // all of the faces left in outside are real surface faces
  585. SaveOutside(b1, hull, outside, b1->contents);
  586. }
  587. }
  588. //
  589. // =====================================================================================
  590. //
  591. // =====================================================================================
  592. // EmitPlanes
  593. // =====================================================================================
  594. static void EmitPlanes()
  595. {
  596. int i;
  597. dplane_t* dp;
  598. plane_t* mp;
  599. g_numplanes = g_nummapplanes;
  600. mp = g_mapplanes;
  601. dp = g_dplanes;
  602. for (i = 0; i < g_nummapplanes; i++, mp++, dp++)
  603. {
  604. //if (!(mp->redundant))
  605. //{
  606. // Log("EmitPlanes: plane %i non redundant\n", i);
  607. VectorCopy(mp->normal, dp->normal);
  608. dp->dist = mp->dist;
  609. dp->type = mp->type;
  610. // }
  611. //else
  612. // {
  613. // Log("EmitPlanes: plane %i redundant\n", i);
  614. // }
  615. }
  616. }
  617. // =====================================================================================
  618. // SetModelNumbers
  619. // blah
  620. // =====================================================================================
  621. static void SetModelNumbers()
  622. {
  623. int i;
  624. int models;
  625. char value[10];
  626. models = 1;
  627. for (i = 1; i < g_numentities; i++)
  628. {
  629. if (g_entities[i].numbrushes)
  630. {
  631. safe_snprintf(value, sizeof(value), "*%i", models);
  632. models++;
  633. SetKeyValue(&g_entities[i], "model", value);
  634. }
  635. }
  636. }
  637. // =====================================================================================
  638. // SetLightStyles
  639. // =====================================================================================
  640. #define MAX_SWITCHED_LIGHTS 32
  641. #define MAX_LIGHTTARGETS_NAME 64
  642. static void SetLightStyles()
  643. {
  644. int stylenum;
  645. const char* t;
  646. entity_t* e;
  647. int i, j;
  648. char value[10];
  649. char lighttargets[MAX_SWITCHED_LIGHTS][MAX_LIGHTTARGETS_NAME];
  650. #ifdef ZHLT_TEXLIGHT
  651. bool newtexlight = false;
  652. #endif
  653. // any light that is controlled (has a targetname)
  654. // must have a unique style number generated for it
  655. stylenum = 0;
  656. for (i = 1; i < g_numentities; i++)
  657. {
  658. e = &g_entities[i];
  659. t = ValueForKey(e, "classname");
  660. if (strncasecmp(t, "light", 5))
  661. {
  662. #ifdef ZHLT_TEXLIGHT
  663. //LRC:
  664. // if it's not a normal light entity, allocate it a new style if necessary.
  665. t = ValueForKey(e, "style");
  666. switch (atoi(t))
  667. {
  668. case 0: // not a light, no style, generally pretty boring
  669. continue;
  670. case -1: // normal switchable texlight
  671. safe_snprintf(value, sizeof(value), "%i", 32 + stylenum);
  672. SetKeyValue(e, "style", value);
  673. stylenum++;
  674. continue;
  675. case -2: // backwards switchable texlight
  676. safe_snprintf(value, sizeof(value), "%i", -(32 + stylenum));
  677. SetKeyValue(e, "style", value);
  678. stylenum++;
  679. continue;
  680. case -3: // (HACK) a piggyback texlight: switched on and off by triggering a real light that has the same name
  681. SetKeyValue(e, "style", "0"); // just in case the level designer didn't give it a name
  682. newtexlight = true;
  683. // don't 'continue', fall out
  684. }
  685. //LRC (ends)
  686. #else
  687. continue;
  688. #endif
  689. }
  690. t = ValueForKey(e, "targetname");
  691. if (!t[0])
  692. {
  693. continue;
  694. }
  695. // find this targetname
  696. for (j = 0; j < stylenum; j++)
  697. {
  698. if (!strcmp(lighttargets[j], t))
  699. {
  700. break;
  701. }
  702. }
  703. if (j == stylenum)
  704. {
  705. hlassume(stylenum < MAX_SWITCHED_LIGHTS, assume_MAX_SWITCHED_LIGHTS);
  706. safe_strncpy(lighttargets[j], t, MAX_LIGHTTARGETS_NAME);
  707. stylenum++;
  708. }
  709. safe_snprintf(value, sizeof(value), "%i", 32 + j);
  710. SetKeyValue(e, "style", value);
  711. }
  712. }
  713. // =====================================================================================
  714. // ConvertHintToEmtpy
  715. // =====================================================================================
  716. static void ConvertHintToEmpty()
  717. {
  718. int i;
  719. // Convert HINT brushes to EMPTY after they have been carved by csg
  720. for (i = 0; i < MAX_MAP_BRUSHES; i++)
  721. {
  722. if (g_mapbrushes[i].contents == CONTENTS_HINT)
  723. {
  724. g_mapbrushes[i].contents = CONTENTS_EMPTY;
  725. }
  726. }
  727. }
  728. // =====================================================================================
  729. // WriteBSP
  730. // =====================================================================================
  731. void WriteBSP(const char* const name)
  732. {
  733. char path[_MAX_PATH];
  734. safe_strncpy(path, name, _MAX_PATH);
  735. DefaultExtension(path, ".bsp");
  736. SetModelNumbers();
  737. SetLightStyles();
  738. if (!g_onlyents)
  739. WriteMiptex();
  740. UnparseEntities();
  741. ConvertHintToEmpty();
  742. WriteBSPFile(path);
  743. }
  744. //
  745. // =====================================================================================
  746. //
  747. // AJM: added in function
  748. // =====================================================================================
  749. // CopyGenerictoCLIP
  750. // clips a generic brush
  751. // =====================================================================================
  752. static void CopyGenerictoCLIP(const brush_t* const b)
  753. {
  754. // code blatently ripped from CopySKYtoCLIP()
  755. int i;
  756. entity_t* mapent;
  757. brush_t* newbrush;
  758. mapent = &g_entities[b->entitynum];
  759. mapent->numbrushes++;
  760. newbrush = &g_mapbrushes[g_nummapbrushes];
  761. newbrush->entitynum = b->entitynum;
  762. newbrush->brushnum = g_nummapbrushes - mapent->firstbrush;
  763. newbrush->firstside = g_numbrushsides;
  764. newbrush->numsides = b->numsides;
  765. newbrush->contents = CONTENTS_CLIP;
  766. newbrush->noclip = 0;
  767. for (i = 0; i < b->numsides; i++)
  768. {
  769. int j;
  770. side_t* side = &g_brushsides[g_numbrushsides];
  771. *side = g_brushsides[b->firstside + i];
  772. safe_strncpy(side->td.name, "CLIP", sizeof(side->td.name));
  773. for (j = 0; j < NUM_HULLS; j++)
  774. {
  775. newbrush->hulls[j].faces = NULL;
  776. newbrush->hulls[j].bounds = b->hulls[j].bounds;
  777. }
  778. g_numbrushsides++;
  779. hlassume(g_numbrushsides < MAX_MAP_SIDES, assume_MAX_MAP_SIDES);
  780. }
  781. g_nummapbrushes++;
  782. hlassume(g_nummapbrushes < MAX_MAP_BRUSHES, assume_MAX_MAP_BRUSHES);
  783. }
  784. #ifdef HLCSG_CLIPECONOMY
  785. // AJM: added in
  786. unsigned int BrushClipHullsDiscarded = 0;
  787. unsigned int ClipNodesDiscarded = 0;
  788. //AJM: added in function
  789. static void MarkEntForNoclip(entity_t* ent)
  790. {
  791. int i;
  792. brush_t* b;
  793. for (i = ent->firstbrush; i < ent->firstbrush + ent->numbrushes; i++)
  794. {
  795. b = &g_mapbrushes[i];
  796. b->noclip = 1;
  797. BrushClipHullsDiscarded++;
  798. ClipNodesDiscarded += b->numsides;
  799. }
  800. }
  801. // AJM
  802. // =====================================================================================
  803. // CheckForNoClip
  804. // marks the noclip flag on any brushes that dont need clipnode generation, eg. func_illusionaries
  805. // =====================================================================================
  806. static void CheckForNoClip()
  807. {
  808. int i;
  809. entity_t* ent;
  810. char entclassname[MAX_KEY];
  811. int spawnflags;
  812. if (!g_bClipNazi)
  813. return; // NO CLIP FOR YOU!!!
  814. for (i = 0; i < g_numentities; i++)
  815. {
  816. if (!g_entities[i].numbrushes)
  817. continue; // not a model
  818. if (!i)
  819. continue; // dont waste our time with worldspawn
  820. ent = &g_entities[i];
  821. strcpy_s(entclassname, ValueForKey(ent, "classname"));
  822. spawnflags = atoi(ValueForKey(ent, "spawnflags"));
  823. // condition 0, it's marked noclip (KGP)
  824. if(strlen(ValueForKey(ent,"zhlt_noclip")) && strcmp(ValueForKey(ent,"zhlt_noclip"),"0"))
  825. {
  826. MarkEntForNoclip(ent);
  827. }
  828. // condition 1, its a func_illusionary
  829. else if (!strncasecmp(entclassname, "func_illusionary", 16))
  830. {
  831. MarkEntForNoclip(ent);
  832. }
  833. // condition 2, flag 4 (8) is set and it is either a func_door, func_train, momentary_door,
  834. // func_door_rotating or func_tracktrain (passable, not-solid flag )
  835. else if ( (spawnflags & 8)
  836. &&
  837. ( /* NOTE: func_doors as far as i can tell may need clipnodes for their
  838. player collision detection, so for now, they stay out of it. */
  839. (!strncasecmp(entclassname, "func_train", 10))
  840. || (!strncasecmp(entclassname, "func_door", 9))
  841. // || (!strncasecmp(entclassname, "momentary_door", 14))
  842. // || (!strncasecmp(entclassname, "func_door_rotating", 18))
  843. || (!strncasecmp(entclassname, "func_tracktrain", 15))
  844. )
  845. )
  846. {
  847. MarkEntForNoclip(ent);
  848. }
  849. // condition 3: flag 2 (2) is set, and its a func_conveyor (not solid flag)
  850. else if ( (spawnflags & 2) && (!strncasecmp(entclassname, "func_conveyor", 13)) )
  851. {
  852. MarkEntForNoclip(ent);
  853. }
  854. // condition 4: flag 1 (1) is set, and its a func_rot_button (not solid flag)
  855. else if ( (spawnflags & 1) && (!strncasecmp(entclassname, "func_rot_button", 15)) )
  856. {
  857. MarkEntForNoclip(ent);
  858. }
  859. // condition 5: flag 7 (64) is set, and its a func_rotating
  860. else if ( (spawnflags & 64) && (!strncasecmp(entclassname, "func_rotating", 13)) )
  861. {
  862. MarkEntForNoclip(ent);
  863. }
  864. /*
  865. // condition 6: its a func_wall, while we noclip it, we remake the clipnodes manually
  866. else if (!strncasecmp(entclassname, "func_wall", 9))
  867. {
  868. for (int j = ent->firstbrush; j < ent->firstbrush + ent->numbrushes; j++)
  869. CopyGenerictoCLIP(&g_mapbrushes[i]);
  870. MarkEntForNoclip(ent);
  871. }
  872. */
  873. }
  874. Log("Brushes discarded from clipping hulls: %i (totalling %i sides)\n", BrushClipHullsDiscarded, ClipNodesDiscarded);
  875. }
  876. #endif
  877. // =====================================================================================
  878. // ProcessModels
  879. // =====================================================================================
  880. #define NUM_TYPECONTENTS 5 // AJM: should reflect the number of values below
  881. int typecontents[NUM_TYPECONTENTS] = {
  882. CONTENTS_WATER, CONTENTS_SLIME, CONTENTS_LAVA, CONTENTS_SKY, CONTENTS_HINT
  883. };
  884. static void ProcessModels()
  885. {
  886. int i, j, type;
  887. int placed;
  888. int first, contents;
  889. brush_t temp;
  890. for (i = 0; i < g_numentities; i++)
  891. {
  892. if (!g_entities[i].numbrushes) // only models
  893. continue;
  894. // sort the contents down so stone bites water, etc
  895. first = g_entities[i].firstbrush;
  896. placed = 0;
  897. for (type = 0; type < NUM_TYPECONTENTS; type++) // for each of the contents types
  898. {
  899. contents = typecontents[type];
  900. for (j = placed + 1; j < g_entities[i].numbrushes; j++) // for each of the model's brushes
  901. {
  902. // if this brush is of the contents type in this for iteration
  903. if (g_mapbrushes[first + j].contents == contents)
  904. {
  905. temp = g_mapbrushes[first + placed];
  906. g_mapbrushes[first + placed] = g_mapbrushes[j];
  907. g_mapbrushes[j] = temp;
  908. placed++;
  909. }
  910. }
  911. }
  912. // csg them in order
  913. if (i == 0) // if its worldspawn....
  914. {
  915. NamedRunThreadsOnIndividual(g_entities[i].numbrushes, g_estimate, CSGBrush);
  916. CheckFatal();
  917. }
  918. else
  919. {
  920. for (j = 0; j < g_entities[i].numbrushes; j++)
  921. {
  922. CSGBrush(first + j);
  923. }
  924. }
  925. // write end of model marker
  926. for (j = 0; j < NUM_HULLS; j++)
  927. {
  928. fprintf(out[j], "-1 -1 -1 -1\n");
  929. }
  930. }
  931. }
  932. // =====================================================================================
  933. // SetModelCenters
  934. // =====================================================================================
  935. static void SetModelCenters(int entitynum)
  936. {
  937. int i;
  938. int last;
  939. char string[MAXTOKEN];
  940. entity_t* e = &g_entities[entitynum];
  941. BoundingBox bounds;
  942. vec3_t center;
  943. if ((entitynum == 0) || (e->numbrushes == 0)) // skip worldspawn and point entities
  944. return;
  945. if (!*ValueForKey(e, "light_origin")) // skip if its not a zhlt_flags light_origin
  946. return;
  947. for (i = e->firstbrush, last = e->firstbrush + e->numbrushes; i < last; i++)
  948. {
  949. if (g_mapbrushes[i].contents != CONTENTS_ORIGIN)
  950. {
  951. bounds.add(g_mapbrushes[i].hulls->bounds);
  952. }
  953. }
  954. VectorAdd(bounds.m_Mins, bounds.m_Maxs, center);
  955. VectorScale(center, 0.5, center);
  956. safe_snprintf(string, MAXTOKEN, "%i %i %i", (int)center[0], (int)center[1], (int)center[2]);
  957. SetKeyValue(e, "model_center", string);
  958. }
  959. //
  960. // =====================================================================================
  961. //
  962. // =====================================================================================
  963. // BoundWorld
  964. // =====================================================================================
  965. static void BoundWorld()
  966. {
  967. int i;
  968. brushhull_t* h;
  969. world_bounds.reset();
  970. for (i = 0; i < g_nummapbrushes; i++)
  971. {
  972. h = &g_mapbrushes[i].hulls[0];
  973. if (!h->faces)
  974. {
  975. continue;
  976. }
  977. world_bounds.add(h->bounds);
  978. }
  979. Verbose("World bounds: (%i %i %i) to (%i %i %i)\n",
  980. (int)world_bounds.m_Mins[0], (int)world_bounds.m_Mins[1], (int)world_bounds.m_Mins[2],
  981. (int)world_bounds.m_Maxs[0], (int)world_bounds.m_Maxs[1], (int)world_bounds.m_Maxs[2]);
  982. }
  983. // =====================================================================================
  984. // Usage
  985. // prints out usage sheet
  986. // =====================================================================================
  987. static void Usage()
  988. {
  989. Banner(); // TODO: Call banner from main CSG process?
  990. Log("\n-= %s Options =-\n\n", g_Program);
  991. Log(" -nowadtextures : include all used textures into bsp\n");
  992. Log(" -wadinclude file : place textures used from wad specified into bsp\n");
  993. Log(" -noclip : don't create clipping hull\n");
  994. #ifdef HLCSG_CLIPECONOMY // AJM
  995. Log(" -noclipeconomy : turn clipnode economy mode off\n");
  996. #endif
  997. #ifdef HLCSG_PRECISIONCLIP // KGP
  998. Log(" -cliptype value : set to smallest, normalized, simple, precise, or legacy (default)\n");
  999. #endif
  1000. #ifdef HLCSG_NULLIFY_INVISIBLE // KGP
  1001. Log(" -nullfile file : specify list of entities to retexture with NULL\n");
  1002. #endif
  1003. Log(" -onlyents : do an entity update from .map to .bsp\n");
  1004. Log(" -noskyclip : disable automatic clipping of SKY brushes\n");
  1005. Log(" -tiny # : minmum brush face surface area before it is discarded\n");
  1006. Log(" -brushunion # : threshold to warn about overlapping brushes\n\n");
  1007. Log(" -hullfile file : Reads in custom collision hull dimensions\n");
  1008. Log(" -texdata # : Alter maximum texture memory limit (in kb)\n");
  1009. Log(" -lightdata # : Alter maximum lighting memory limit (in kb)\n");
  1010. Log(" -chart : display bsp statitics\n");
  1011. Log(" -low | -high : run program an altered priority level\n");
  1012. Log(" -nolog : don't generate the compile logfiles\n");
  1013. Log(" -threads # : manually specify the number of threads to run\n");
  1014. Log(" -noconcolors : Disable Windows console text coloring\n");
  1015. #ifdef SYSTEM_WIN32
  1016. Log(" -estimate : display estimated time during compile\n");
  1017. #endif
  1018. #ifdef ZHLT_PROGRESSFILE // AJM
  1019. Log(" -progressfile path : specify the path to a file for progress estimate output\n");
  1020. #endif
  1021. #ifdef SYSTEM_POSIX
  1022. Log(" -noestimate : do not display continuous compile time estimates\n");
  1023. #endif
  1024. Log(" -verbose : compile with verbose messages\n");
  1025. Log(" -noinfo : Do not show tool configuration information\n");
  1026. #ifdef ZHLT_NULLTEX // AJM
  1027. Log(" -nonulltex : Turns off null texture stripping\n");
  1028. #endif
  1029. #ifdef ZHLT_DETAIL // AJM
  1030. Log(" -nodetail : dont handle detail brushes\n");
  1031. #endif
  1032. Log(" -dev # : compile with developer message\n\n");
  1033. #ifdef HLCSG_WADCFG // AJM
  1034. Log(" -wadconfig name : Specify a configuration to use from wad.cfg\n");
  1035. Log(" -wadcfgfile path : Manually specify a path to the wad.cfg file\n"); //JK:
  1036. #endif
  1037. #ifdef HLCSG_AUTOWAD // AJM:
  1038. Log(" -wadautodetect : Force auto-detection of wadfiles\n");
  1039. #endif
  1040. Log(" mapfile : The mapfile to compile\n\n");
  1041. exit(1);
  1042. }
  1043. // =====================================================================================
  1044. // DumpWadinclude
  1045. // prints out the wadinclude list
  1046. // =====================================================================================
  1047. static void DumpWadinclude()
  1048. {
  1049. Log("Wadinclude list :\n");
  1050. WadInclude_i it;
  1051. for (it = g_WadInclude.begin(); it != g_WadInclude.end(); it++)
  1052. {
  1053. Log("[%s]\n", it->c_str());
  1054. }
  1055. }
  1056. // =====================================================================================
  1057. // Settings
  1058. // prints out settings sheet
  1059. // =====================================================================================
  1060. static void Settings()
  1061. {
  1062. char* tmp;
  1063. if (!g_info)
  1064. return;
  1065. Log("\nCurrent %s Settings\n", g_Program);
  1066. Log("Name | Setting | Default\n"
  1067. "---------------------|-------------|-------------------------\n");
  1068. // ZHLT Common Settings
  1069. if (DEFAULT_NUMTHREADS == -1)
  1070. {
  1071. Log("threads [ %9d ] [ Varies ]\n", g_numthreads);
  1072. }
  1073. else
  1074. {
  1075. Log("threads [ %9d ] [ %9d ]\n", g_numthreads, DEFAULT_NUMTHREADS);
  1076. }
  1077. Log("verbose [ %9s ] [ %9s ]\n", g_verbose ? "on" : "off", DEFAULT_VERBOSE ? "on" : "off");
  1078. Log("log [ %9s ] [ %9s ]\n", g_log ? "on" : "off", DEFAULT_LOG ? "on" : "off");
  1079. Log("developer [ %9d ] [ %9d ]\n", g_developer, DEFAULT_DEVELOPER);
  1080. Log("chart [ %9s ] [ %9s ]\n", g_chart ? "on" : "off", DEFAULT_CHART ? "on" : "off");
  1081. Log("estimate [ %9s ] [ %9s ]\n", g_estimate ? "on" : "off", DEFAULT_ESTIMATE ? "on" : "off");
  1082. Log("max texture memory [ %9d ] [ %9d ]\n", g_max_map_miptex, DEFAULT_MAX_MAP_MIPTEX);
  1083. Log("max lighting memory [ %9d ] [ %9d ]\n", g_max_map_lightdata, DEFAULT_MAX_MAP_LIGHTDATA);
  1084. switch (g_threadpriority)
  1085. {
  1086. case eThreadPriorityNormal:
  1087. default:
  1088. tmp = "Normal";
  1089. break;
  1090. case eThreadPriorityLow:
  1091. tmp = "Low";
  1092. break;
  1093. case eThreadPriorityHigh:
  1094. tmp = "High";
  1095. break;
  1096. }
  1097. Log("priority [ %9s ] [ %9s ]\n", tmp, "Normal");
  1098. Log("\n");
  1099. // HLCSG Specific Settings
  1100. Log("noclip [ %9s ] [ %9s ]\n", g_noclip ? "on" : "off", DEFAULT_NOCLIP ? "on" : "off");
  1101. #ifdef ZHLT_NULLTEX // AJM:
  1102. Log("null texture stripping[ %9s ] [ %9s ]\n", g_bUseNullTex ? "on" : "off", DEFAULT_NULLTEX ? "on" : "off");
  1103. #endif
  1104. #ifdef ZHLT_DETAIL // AJM
  1105. Log("detail brushes [ %9s ] [ %9s ]\n", g_bDetailBrushes ? "on" : "off", DEFAULT_DETAIL ? "on" : "off");
  1106. #endif
  1107. #ifdef HLCSG_CLIPECONOMY // AJM
  1108. Log("clipnode economy mode [ %9s ] [ %9s ]\n", g_bClipNazi ? "on" : "off", DEFAULT_CLIPNAZI ? "on" : "off");
  1109. #endif
  1110. #ifdef HLCSG_PRECISIONCLIP // KGP
  1111. Log("clip hull type [ %9s ] [ %9s ]\n", GetClipTypeString(g_cliptype), GetClipTypeString(DEFAULT_CLIPTYPE));
  1112. #endif
  1113. Log("onlyents [ %9s ] [ %9s ]\n", g_onlyents ? "on" : "off", DEFAULT_ONLYENTS ? "on" : "off");
  1114. Log("wadtextures [ %9s ] [ %9s ]\n", g_wadtextures ? "on" : "off", DEFAULT_WADTEXTURES ? "on" : "off");
  1115. Log("skyclip [ %9s ] [ %9s ]\n", g_skyclip ? "on" : "off", DEFAULT_SKYCLIP ? "on" : "off");
  1116. Log("hullfile [ %9s ] [ %9s ]\n", g_hullfile ? g_hullfile : "None", "None");
  1117. #ifdef HLCSG_NULLIFY_INVISIBLE // KGP
  1118. Log("nullfile [ %9s ] [ %9s ]\n", g_nullfile ? g_nullfile : "None", "None");
  1119. #endif
  1120. // calc min surface area
  1121. {
  1122. char tiny_penetration[10];
  1123. char default_tiny_penetration[10];
  1124. safe_snprintf(tiny_penetration, sizeof(tiny_penetration), "%3.3f", g_tiny_threshold);
  1125. safe_snprintf(default_tiny_penetration, sizeof(default_tiny_penetration), "%3.3f", DEFAULT_TINY_THRESHOLD);
  1126. Log("min surface area [ %9s ] [ %9s ]\n", tiny_penetration, default_tiny_penetration);
  1127. }
  1128. // calc union threshold
  1129. {
  1130. char brush_union[10];
  1131. char default_brush_union[10];
  1132. safe_snprintf(brush_union, sizeof(brush_union), "%3.3f", g_BrushUnionThreshold);
  1133. safe_snprintf(default_brush_union, sizeof(default_brush_union), "%3.3f", DEFAULT_BRUSH_UNION_THRESHOLD);
  1134. Log("brush union threshold [ %9s ] [ %9s ]\n", brush_union, default_brush_union);
  1135. }
  1136. Log("\n");
  1137. }
  1138. // AJM: added in
  1139. // =====================================================================================
  1140. // CSGCleanup
  1141. // =====================================================================================
  1142. void CSGCleanup()
  1143. {
  1144. //Log("CSGCleanup\n");
  1145. #ifdef HLCSG_AUTOWAD
  1146. autowad_cleanup();
  1147. #endif
  1148. #ifdef HLCSG_WADCFG
  1149. WadCfg_cleanup();
  1150. #endif
  1151. #ifdef HLCSG_NULLIFY_TEXTURES
  1152. properties_cleanup();
  1153. #endif
  1154. FreeWadPaths();
  1155. }
  1156. // =====================================================================================
  1157. // Main
  1158. // Oh, come on.
  1159. // =====================================================================================
  1160. int main(const int argc, char** argv)
  1161. {
  1162. int i;
  1163. char name[_MAX_PATH]; // mapanme
  1164. double start, end; // start/end time log
  1165. const char* mapname_from_arg = NULL; // mapname path from passed argvar
  1166. g_Program = "hlcsg";
  1167. if (argc == 1)
  1168. Usage();
  1169. // Hard coded list of -wadinclude files, used for HINT texture brushes so lazy
  1170. // mapmakers wont cause beta testers (or possibly end users) to get a wad
  1171. // error on zhlt.wad etc
  1172. g_WadInclude.push_back("zhlt.wad");
  1173. memset(wadconfigname, 0, sizeof(wadconfigname));//AJM
  1174. // detect argv
  1175. for (i = 1; i < argc; i++)
  1176. {
  1177. if (!strcasecmp(argv[i], "-threads"))
  1178. {
  1179. if (i < argc)
  1180. {
  1181. g_numthreads = atoi(argv[++i]);
  1182. if (g_numthreads < 1)
  1183. {
  1184. Log("Expected value of at least 1 for '-threads'\n");
  1185. Usage();
  1186. }
  1187. }
  1188. else
  1189. {
  1190. Usage();
  1191. }
  1192. }
  1193. #ifdef SYSTEM_WIN32
  1194. else if (!strcasecmp(argv[i], "-estimate"))
  1195. {
  1196. g_estimate = true;
  1197. }
  1198. #endif
  1199. #ifdef SYSTEM_POSIX
  1200. else if (!strcasecmp(argv[i], "-noestimate"))
  1201. {
  1202. g_estimate = false;
  1203. }
  1204. #endif
  1205. else if (!strcasecmp(argv[i], "-dev"))
  1206. {
  1207. if (i < argc)
  1208. {
  1209. g_developer = (developer_level_t)atoi(argv[++i]);
  1210. }
  1211. else
  1212. {
  1213. Usage();
  1214. }
  1215. }
  1216. else if (!strcasecmp(argv[i], "-verbose"))
  1217. {
  1218. g_verbose = true;
  1219. }
  1220. else if (!strcasecmp(argv[i], "-noinfo"))
  1221. {
  1222. g_info = false;
  1223. }
  1224. else if (!strcasecmp(argv[i], "-chart"))
  1225. {
  1226. g_chart = true;
  1227. }
  1228. else if (!strcasecmp(argv[i], "-low"))
  1229. {
  1230. g_threadpriority = eThreadPriorityLow;
  1231. }
  1232. else if (!strcasecmp(argv[i], "-high"))
  1233. {
  1234. g_threadpriority = eThreadPriorityHigh;
  1235. }
  1236. else if (!strcasecmp(argv[i], "-nolog"))
  1237. {
  1238. g_log = false;
  1239. }
  1240. else if (!strcasecmp(argv[i], "-skyclip"))
  1241. {
  1242. g_skyclip = true;
  1243. }
  1244. else if (!strcasecmp(argv[i], "-noskyclip"))
  1245. {
  1246. g_skyclip = false;
  1247. }
  1248. else if (!strcasecmp(argv[i], "-noclip"))
  1249. {
  1250. g_noclip = true;
  1251. }
  1252. else if (!strcasecmp(argv[i], "-onlyents"))
  1253. {
  1254. g_onlyents = true;
  1255. }
  1256. #ifdef ZHLT_NULLTEX // AJM: added in -nonulltex
  1257. else if (!strcasecmp(argv[i], "-nonulltex"))
  1258. {
  1259. g_bUseNullTex = false;
  1260. }
  1261. #endif
  1262. #ifdef HLCSG_CLIPECONOMY // AJM: added in -noclipeconomy
  1263. else if (!strcasecmp(argv[i], "-noclipeconomy"))
  1264. {
  1265. g_bClipNazi = false;
  1266. }
  1267. #endif
  1268. #ifdef HLCSG_PRECISIONCLIP // KGP: added in -cliptype
  1269. else if (!strcasecmp(argv[i], "-cliptype"))
  1270. {
  1271. if (i < argc)
  1272. {
  1273. ++i;
  1274. if(!strcasecmp(argv[i],"smallest"))
  1275. { g_cliptype = clip_smallest; }
  1276. else if(!strcasecmp(argv[i],"normalized"))
  1277. { g_cliptype = clip_normalized; }
  1278. else if(!strcasecmp(argv[i],"simple"))
  1279. { g_cliptype = clip_simple; }
  1280. else if(!strcasecmp(argv[i],"precise"))
  1281. { g_cliptype = clip_precise; }
  1282. else if(!strcasecmp(argv[i],"legacy"))
  1283. { g_cliptype = clip_legacy; }
  1284. }
  1285. else
  1286. {
  1287. Log("Error: -cliptype: incorrect usage of parameter\n");
  1288. Usage();
  1289. }
  1290. }
  1291. #endif
  1292. #ifdef HLCSG_WADCFG
  1293. // AJM: added in -wadconfig
  1294. else if (!strcasecmp(argv[i], "-wadconfig"))
  1295. {
  1296. if (i < argc)
  1297. {
  1298. safe_strncpy(wadconfigname, argv[++i], MAX_WAD_CFG_NAME);
  1299. if (strlen(argv[i]) > MAX_WAD_CFG_NAME)
  1300. {
  1301. Warning("wad configuration name was truncated to %i chars", MAX_WAD_CFG_NAME);
  1302. wadconfigname[MAX_WAD_CFG_NAME] = 0;
  1303. }
  1304. }
  1305. else
  1306. {
  1307. Log("Error: -wadconfig: incorrect usage of parameter\n");
  1308. Usage();
  1309. }
  1310. }
  1311. //JK: added in -wadcfgfile
  1312. else if (!strcasecmp(argv[i], "-wadcfgfile"))
  1313. {
  1314. if (i < argc)
  1315. {
  1316. g_wadcfgfile = argv[++i];
  1317. }
  1318. else
  1319. {
  1320. Log("Error: -wadcfgfile: incorrect usage of parameter\n");
  1321. Usage();
  1322. }
  1323. }
  1324. #endif
  1325. #ifdef HLCSG_NULLIFY_INVISIBLE
  1326. else if (!strcasecmp(argv[i], "-nullfile"))
  1327. {
  1328. if (i < argc)
  1329. {
  1330. g_nullfile = argv[++i];
  1331. }
  1332. else
  1333. {
  1334. Log("Error: -nullfile: expected path to null ent file following parameter\n");
  1335. Usage();
  1336. }
  1337. }
  1338. #endif
  1339. #ifdef HLCSG_AUTOWAD // AJM
  1340. else if (!strcasecmp(argv[i], "-wadautodetect"))
  1341. {
  1342. g_bWadAutoDetect = true;
  1343. }
  1344. #endif
  1345. #ifdef ZHLT_DETAIL // AJM
  1346. else if (!strcasecmp(argv[i], "-nodetail"))
  1347. {
  1348. g_bDetailBrushes = false;
  1349. }
  1350. #endif
  1351. #ifdef ZHLT_PROGRESSFILE // AJM
  1352. else if (!strcasecmp(argv[i], "-progressfile"))
  1353. {
  1354. if (i < argc)
  1355. {
  1356. g_progressfile = argv[++i];
  1357. }
  1358. else
  1359. {
  1360. Log("Error: -progressfile: expected path to progress file following parameter\n");
  1361. Usage();
  1362. }
  1363. }
  1364. #endif
  1365. else if (!strcasecmp(argv[i], "-nowadtextures"))
  1366. {
  1367. g_wadtextures = false;
  1368. }
  1369. else if (!strcasecmp(argv[i], "-wadinclude"))
  1370. {
  1371. if (i < argc)
  1372. {
  1373. g_WadInclude.push_back(argv[++i]);
  1374. }
  1375. else
  1376. {
  1377. Usage();
  1378. }
  1379. }
  1380. else if (!strcasecmp(argv[i], "-texdata"))
  1381. {
  1382. if (i < argc)
  1383. {
  1384. int x = atoi(argv[++i]) * 1024;
  1385. if (x > g_max_map_miptex)
  1386. {
  1387. g_max_map_miptex = x;
  1388. }
  1389. }
  1390. else
  1391. {
  1392. Usage();
  1393. }
  1394. }
  1395. else if (!strcasecmp(argv[i], "-lightdata"))
  1396. {
  1397. if (i < argc)
  1398. {
  1399. int x = atoi(argv[++i]) * 1024;
  1400. if (x > g_max_map_lightdata)
  1401. {
  1402. g_max_map_lightdata = x;
  1403. }
  1404. }
  1405. else
  1406. {
  1407. Usage();
  1408. }
  1409. }
  1410. else if (!strcasecmp(argv[i], "-brushunion"))
  1411. {
  1412. if (i < argc)
  1413. {
  1414. g_BrushUnionThreshold = (float)atof(argv[++i]);
  1415. }
  1416. else
  1417. {
  1418. Usage();
  1419. }
  1420. }
  1421. else if (!strcasecmp(argv[i], "-tiny"))
  1422. {
  1423. if (i < argc)
  1424. {
  1425. g_tiny_threshold = (float)atof(argv[++i]);
  1426. }
  1427. else
  1428. {
  1429. Usage();
  1430. }
  1431. }
  1432. else if (!strcasecmp(argv[i], "-hullfile"))
  1433. {
  1434. if (i < argc)
  1435. {
  1436. g_hullfile = argv[++i];
  1437. }
  1438. else
  1439. {
  1440. Usage();
  1441. }
  1442. }
  1443. // SILENCER -->
  1444. else if (!strcasecmp(argv[i], "-noconcolors"))
  1445. {
  1446. g_noConColors = true;
  1447. }
  1448. // <-- SILENCER
  1449. else if (argv[i][0] == '-')
  1450. {
  1451. Log("Unknown option \"%s\"\n", argv[i]);
  1452. Usage();
  1453. }
  1454. else if (!mapname_from_arg)
  1455. {
  1456. mapname_from_arg = argv[i];
  1457. }
  1458. else
  1459. {
  1460. Log("Unknown option \"%s\"\n", argv[i]);
  1461. Usage();
  1462. }
  1463. }
  1464. // no mapfile?
  1465. if (!mapname_from_arg)
  1466. {
  1467. // what a shame.
  1468. Log("No mapfile specified\n");
  1469. Usage();
  1470. }
  1471. // handle mapname
  1472. safe_strncpy(g_Mapname, mapname_from_arg, _MAX_PATH);
  1473. FlipSlashes(g_Mapname);
  1474. StripExtension(g_Mapname);
  1475. // onlyents
  1476. if (!g_onlyents)
  1477. ResetTmpFiles();
  1478. // other stuff
  1479. ResetErrorLog();
  1480. ResetLog();
  1481. OpenLog(g_clientid);
  1482. atexit(CloseLog);
  1483. LogStart(argc, argv);
  1484. atexit(CSGCleanup); // AJM
  1485. dtexdata_init();
  1486. atexit(dtexdata_free);
  1487. // START CSG
  1488. // AJM: re-arranged some stuff up here so that the mapfile is loaded
  1489. // before settings are finalised and printed out, so that the info_compile_parameters
  1490. // entity can be dealt with effectively
  1491. start = I_FloatTime();
  1492. LoadHullfile(g_hullfile); // if the user specified a hull file, load it now
  1493. #ifdef HLCSG_NULLIFY_INVISIBLE
  1494. if(g_bUseNullTex)
  1495. { properties_initialize(g_nullfile); }
  1496. #endif
  1497. safe_strncpy(name, mapname_from_arg, _MAX_PATH); // make a copy of the nap name
  1498. DefaultExtension(name, ".map"); // might be .reg
  1499. LoadMapFile(name);
  1500. ThreadSetDefault();
  1501. ThreadSetPriority(g_threadpriority);
  1502. Settings();
  1503. #ifdef HLCSG_WADCFG // AJM
  1504. // figure out what to do with the texture settings
  1505. if (wadconfigname[0]) // custom wad configuations will take precedence
  1506. {
  1507. LoadWadConfigFile();
  1508. ProcessWadConfiguration();
  1509. }
  1510. else
  1511. {
  1512. Log("Using mapfile wad configuration\n");
  1513. }
  1514. if (!g_bWadConfigsLoaded) // dont try and override wad.cfg
  1515. #endif
  1516. {
  1517. GetUsedWads();
  1518. }
  1519. #ifdef HLCSG_AUTOWAD
  1520. if (g_bWadAutoDetect)
  1521. {
  1522. Log("Wadfiles not in use by the map will be excluded\n");
  1523. }
  1524. #endif
  1525. DumpWadinclude();
  1526. Log("\n");
  1527. // if onlyents, just grab the entites and resave
  1528. if (g_onlyents)
  1529. {
  1530. char out[_MAX_PATH];
  1531. safe_snprintf(out, _MAX_PATH, "%s.bsp", g_Mapname);
  1532. LoadBSPFile(out);
  1533. LoadWadincludeFile(g_Mapname);
  1534. HandleWadinclude();
  1535. // Write it all back out again.
  1536. if (g_chart)
  1537. {
  1538. PrintBSPFileSizes();
  1539. }
  1540. WriteBSP(g_Mapname);
  1541. end = I_FloatTime();
  1542. LogTimeElapsed(end - start);
  1543. return 0;
  1544. }
  1545. else
  1546. {
  1547. SaveWadincludeFile(g_Mapname);
  1548. }
  1549. #ifdef HLCSG_CLIPECONOMY // AJM
  1550. CheckForNoClip();
  1551. #endif
  1552. // createbrush
  1553. NamedRunThreadsOnIndividual(g_nummapbrushes, g_estimate, CreateBrush);
  1554. CheckFatal();
  1555. #ifdef HLCSG_PRECISIONCLIP // KGP - drop TEX_BEVEL flag
  1556. FixBevelTextures();
  1557. #endif
  1558. // boundworld
  1559. BoundWorld();
  1560. Verbose("%5i map planes\n", g_nummapplanes);
  1561. // Set model centers
  1562. NamedRunThreadsOnIndividual(g_numentities, g_estimate, SetModelCenters);
  1563. // Calc brush unions
  1564. if ((g_BrushUnionThreshold > 0.0) && (g_BrushUnionThreshold <= 100.0))
  1565. {
  1566. NamedRunThreadsOnIndividual(g_nummapbrushes, g_estimate, CalculateBrushUnions);
  1567. }
  1568. // open hull files
  1569. for (i = 0; i < NUM_HULLS; i++)
  1570. {
  1571. char name[_MAX_PATH];
  1572. safe_snprintf(name, _MAX_PATH, "%s.p%i", g_Mapname, i);
  1573. out[i] = fopen(name, "w");
  1574. if (!out[i])
  1575. Error("Couldn't open %s", name);
  1576. }
  1577. ProcessModels();
  1578. Verbose("%5i csg faces\n", c_csgfaces);
  1579. Verbose("%5i used faces\n", c_outfaces);
  1580. Verbose("%5i tiny faces\n", c_tiny);
  1581. Verbose("%5i tiny clips\n", c_tiny_clip);
  1582. // close hull files
  1583. for (i = 0; i < NUM_HULLS; i++)
  1584. fclose(out[i]);
  1585. EmitPlanes();
  1586. if (g_chart)
  1587. PrintBSPFileSizes();
  1588. WriteBSP(g_Mapname);
  1589. // AJM: debug
  1590. #if 0
  1591. Log("\n---------------------------------------\n"
  1592. "Map Plane Usage:\n"
  1593. " # normal origin dist type\n"
  1594. " ( x, y, z) ( x, y, z) ( )\n"
  1595. );
  1596. for (i = 0; i < g_nummapplanes; i++)
  1597. {
  1598. plane_t* p = &g_mapplanes[i];
  1599. Log(
  1600. "%3i (%4.0f, %4.0f, %4.0f) (%4.0f, %4.0f, %4.0f) (%5.0f) %i\n",
  1601. i,
  1602. p->normal[1], p->normal[2], p->normal[3],
  1603. p->origin[1], p->origin[2], p->origin[3],
  1604. p->dist,
  1605. p->type
  1606. );
  1607. }
  1608. Log("---------------------------------------\n\n");
  1609. #endif
  1610. // elapsed time
  1611. end = I_FloatTime();
  1612. LogTimeElapsed(end - start);
  1613. return 0;
  1614. }