qcsg.cpp 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895
  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. #ifndef HLCSG_SORTBRUSH_FIX
  881. #define NUM_TYPECONTENTS 5 // AJM: should reflect the number of values below
  882. int typecontents[NUM_TYPECONTENTS] = {
  883. CONTENTS_WATER, CONTENTS_SLIME, CONTENTS_LAVA, CONTENTS_SKY, CONTENTS_HINT
  884. };
  885. #endif
  886. static void ProcessModels()
  887. {
  888. int i, j;
  889. #ifndef HLCSG_SORTBRUSH_FIX
  890. int type;
  891. #endif
  892. int placed;
  893. int first, contents;
  894. brush_t temp;
  895. for (i = 0; i < g_numentities; i++)
  896. {
  897. if (!g_entities[i].numbrushes) // only models
  898. continue;
  899. #ifdef HLCSG_SORTBRUSH_FIX
  900. first = g_entities[i].firstbrush;
  901. placed = 0;
  902. while (placed < g_entities[i].numbrushes)
  903. {
  904. for (j = placed; j < g_entities[i].numbrushes; j++)
  905. {
  906. if (j == placed)
  907. {
  908. contents = g_mapbrushes[first + j].contents;
  909. }
  910. else
  911. {
  912. contents = min(g_mapbrushes[first + j].contents, contents);
  913. }
  914. }
  915. for (j = placed; j < g_entities[i].numbrushes; j++)
  916. {
  917. if (g_mapbrushes[first + j].contents == contents)
  918. {
  919. temp = g_mapbrushes[first + placed];
  920. g_mapbrushes[first + placed] = g_mapbrushes[first + j];
  921. g_mapbrushes[first + j] = temp;
  922. placed++;
  923. }
  924. }
  925. }
  926. #else
  927. first = g_entities[i].firstbrush;
  928. placed = 0;
  929. for (type = 0; type < NUM_TYPECONTENTS; type++) // for each of the contents types
  930. {
  931. contents = typecontents[type];
  932. for (j = placed + 1; j < g_entities[i].numbrushes; j++) // for each of the model's brushes
  933. {
  934. // if this brush is of the contents type in this for iteration
  935. if (g_mapbrushes[first + j].contents == contents)
  936. {
  937. temp = g_mapbrushes[first + placed];
  938. g_mapbrushes[first + placed] = g_mapbrushes[j];
  939. g_mapbrushes[j] = temp;
  940. placed++;
  941. }
  942. }
  943. }
  944. #endif
  945. // csg them in order
  946. if (i == 0) // if its worldspawn....
  947. {
  948. NamedRunThreadsOnIndividual(g_entities[i].numbrushes, g_estimate, CSGBrush);
  949. CheckFatal();
  950. }
  951. else
  952. {
  953. for (j = 0; j < g_entities[i].numbrushes; j++)
  954. {
  955. CSGBrush(first + j);
  956. }
  957. }
  958. // write end of model marker
  959. for (j = 0; j < NUM_HULLS; j++)
  960. {
  961. fprintf(out[j], "-1 -1 -1 -1\n");
  962. }
  963. }
  964. }
  965. // =====================================================================================
  966. // SetModelCenters
  967. // =====================================================================================
  968. static void SetModelCenters(int entitynum)
  969. {
  970. int i;
  971. int last;
  972. char string[MAXTOKEN];
  973. entity_t* e = &g_entities[entitynum];
  974. BoundingBox bounds;
  975. vec3_t center;
  976. if ((entitynum == 0) || (e->numbrushes == 0)) // skip worldspawn and point entities
  977. return;
  978. if (!*ValueForKey(e, "light_origin")) // skip if its not a zhlt_flags light_origin
  979. return;
  980. for (i = e->firstbrush, last = e->firstbrush + e->numbrushes; i < last; i++)
  981. {
  982. if (g_mapbrushes[i].contents != CONTENTS_ORIGIN)
  983. {
  984. bounds.add(g_mapbrushes[i].hulls->bounds);
  985. }
  986. }
  987. VectorAdd(bounds.m_Mins, bounds.m_Maxs, center);
  988. VectorScale(center, 0.5, center);
  989. safe_snprintf(string, MAXTOKEN, "%i %i %i", (int)center[0], (int)center[1], (int)center[2]);
  990. SetKeyValue(e, "model_center", string);
  991. }
  992. //
  993. // =====================================================================================
  994. //
  995. // =====================================================================================
  996. // BoundWorld
  997. // =====================================================================================
  998. static void BoundWorld()
  999. {
  1000. int i;
  1001. brushhull_t* h;
  1002. world_bounds.reset();
  1003. for (i = 0; i < g_nummapbrushes; i++)
  1004. {
  1005. h = &g_mapbrushes[i].hulls[0];
  1006. if (!h->faces)
  1007. {
  1008. continue;
  1009. }
  1010. world_bounds.add(h->bounds);
  1011. }
  1012. Verbose("World bounds: (%i %i %i) to (%i %i %i)\n",
  1013. (int)world_bounds.m_Mins[0], (int)world_bounds.m_Mins[1], (int)world_bounds.m_Mins[2],
  1014. (int)world_bounds.m_Maxs[0], (int)world_bounds.m_Maxs[1], (int)world_bounds.m_Maxs[2]);
  1015. }
  1016. // =====================================================================================
  1017. // Usage
  1018. // prints out usage sheet
  1019. // =====================================================================================
  1020. static void Usage()
  1021. {
  1022. Banner(); // TODO: Call banner from main CSG process?
  1023. Log("\n-= %s Options =-\n\n", g_Program);
  1024. Log(" -nowadtextures : include all used textures into bsp\n");
  1025. Log(" -wadinclude file : place textures used from wad specified into bsp\n");
  1026. Log(" -noclip : don't create clipping hull\n");
  1027. #ifdef HLCSG_CLIPECONOMY // AJM
  1028. Log(" -noclipeconomy : turn clipnode economy mode off\n");
  1029. #endif
  1030. #ifdef HLCSG_PRECISIONCLIP // KGP
  1031. Log(" -cliptype value : set to smallest, normalized, simple, precise, or legacy (default)\n");
  1032. #endif
  1033. #ifdef HLCSG_NULLIFY_INVISIBLE // KGP
  1034. Log(" -nullfile file : specify list of entities to retexture with NULL\n");
  1035. #endif
  1036. Log(" -onlyents : do an entity update from .map to .bsp\n");
  1037. Log(" -noskyclip : disable automatic clipping of SKY brushes\n");
  1038. Log(" -tiny # : minmum brush face surface area before it is discarded\n");
  1039. Log(" -brushunion # : threshold to warn about overlapping brushes\n\n");
  1040. Log(" -hullfile file : Reads in custom collision hull dimensions\n");
  1041. Log(" -texdata # : Alter maximum texture memory limit (in kb)\n");
  1042. Log(" -lightdata # : Alter maximum lighting memory limit (in kb)\n");
  1043. Log(" -chart : display bsp statitics\n");
  1044. Log(" -low | -high : run program an altered priority level\n");
  1045. Log(" -nolog : don't generate the compile logfiles\n");
  1046. Log(" -threads # : manually specify the number of threads to run\n");
  1047. Log(" -noconcolors : Disable Windows console text coloring\n");
  1048. #ifdef SYSTEM_WIN32
  1049. Log(" -estimate : display estimated time during compile\n");
  1050. #endif
  1051. #ifdef ZHLT_PROGRESSFILE // AJM
  1052. Log(" -progressfile path : specify the path to a file for progress estimate output\n");
  1053. #endif
  1054. #ifdef SYSTEM_POSIX
  1055. Log(" -noestimate : do not display continuous compile time estimates\n");
  1056. #endif
  1057. Log(" -verbose : compile with verbose messages\n");
  1058. Log(" -noinfo : Do not show tool configuration information\n");
  1059. #ifdef ZHLT_NULLTEX // AJM
  1060. Log(" -nonulltex : Turns off null texture stripping\n");
  1061. #endif
  1062. #ifdef ZHLT_DETAIL // AJM
  1063. Log(" -nodetail : dont handle detail brushes\n");
  1064. #endif
  1065. Log(" -dev # : compile with developer message\n\n");
  1066. #ifdef HLCSG_WADCFG // AJM
  1067. Log(" -wadconfig name : Specify a configuration to use from wad.cfg\n");
  1068. Log(" -wadcfgfile path : Manually specify a path to the wad.cfg file\n"); //JK:
  1069. #endif
  1070. #ifdef HLCSG_AUTOWAD // AJM:
  1071. Log(" -wadautodetect : Force auto-detection of wadfiles\n");
  1072. #endif
  1073. Log(" mapfile : The mapfile to compile\n\n");
  1074. exit(1);
  1075. }
  1076. // =====================================================================================
  1077. // DumpWadinclude
  1078. // prints out the wadinclude list
  1079. // =====================================================================================
  1080. static void DumpWadinclude()
  1081. {
  1082. Log("Wadinclude list :\n");
  1083. WadInclude_i it;
  1084. for (it = g_WadInclude.begin(); it != g_WadInclude.end(); it++)
  1085. {
  1086. Log("[%s]\n", it->c_str());
  1087. }
  1088. }
  1089. // =====================================================================================
  1090. // Settings
  1091. // prints out settings sheet
  1092. // =====================================================================================
  1093. static void Settings()
  1094. {
  1095. char* tmp;
  1096. if (!g_info)
  1097. return;
  1098. Log("\nCurrent %s Settings\n", g_Program);
  1099. Log("Name | Setting | Default\n"
  1100. "---------------------|-------------|-------------------------\n");
  1101. // ZHLT Common Settings
  1102. if (DEFAULT_NUMTHREADS == -1)
  1103. {
  1104. Log("threads [ %9d ] [ Varies ]\n", g_numthreads);
  1105. }
  1106. else
  1107. {
  1108. Log("threads [ %9d ] [ %9d ]\n", g_numthreads, DEFAULT_NUMTHREADS);
  1109. }
  1110. Log("verbose [ %9s ] [ %9s ]\n", g_verbose ? "on" : "off", DEFAULT_VERBOSE ? "on" : "off");
  1111. Log("log [ %9s ] [ %9s ]\n", g_log ? "on" : "off", DEFAULT_LOG ? "on" : "off");
  1112. Log("developer [ %9d ] [ %9d ]\n", g_developer, DEFAULT_DEVELOPER);
  1113. Log("chart [ %9s ] [ %9s ]\n", g_chart ? "on" : "off", DEFAULT_CHART ? "on" : "off");
  1114. Log("estimate [ %9s ] [ %9s ]\n", g_estimate ? "on" : "off", DEFAULT_ESTIMATE ? "on" : "off");
  1115. Log("max texture memory [ %9d ] [ %9d ]\n", g_max_map_miptex, DEFAULT_MAX_MAP_MIPTEX);
  1116. Log("max lighting memory [ %9d ] [ %9d ]\n", g_max_map_lightdata, DEFAULT_MAX_MAP_LIGHTDATA);
  1117. switch (g_threadpriority)
  1118. {
  1119. case eThreadPriorityNormal:
  1120. default:
  1121. tmp = "Normal";
  1122. break;
  1123. case eThreadPriorityLow:
  1124. tmp = "Low";
  1125. break;
  1126. case eThreadPriorityHigh:
  1127. tmp = "High";
  1128. break;
  1129. }
  1130. Log("priority [ %9s ] [ %9s ]\n", tmp, "Normal");
  1131. Log("\n");
  1132. // HLCSG Specific Settings
  1133. Log("noclip [ %9s ] [ %9s ]\n", g_noclip ? "on" : "off", DEFAULT_NOCLIP ? "on" : "off");
  1134. #ifdef ZHLT_NULLTEX // AJM:
  1135. Log("null texture stripping[ %9s ] [ %9s ]\n", g_bUseNullTex ? "on" : "off", DEFAULT_NULLTEX ? "on" : "off");
  1136. #endif
  1137. #ifdef ZHLT_DETAIL // AJM
  1138. Log("detail brushes [ %9s ] [ %9s ]\n", g_bDetailBrushes ? "on" : "off", DEFAULT_DETAIL ? "on" : "off");
  1139. #endif
  1140. #ifdef HLCSG_CLIPECONOMY // AJM
  1141. Log("clipnode economy mode [ %9s ] [ %9s ]\n", g_bClipNazi ? "on" : "off", DEFAULT_CLIPNAZI ? "on" : "off");
  1142. #endif
  1143. #ifdef HLCSG_PRECISIONCLIP // KGP
  1144. Log("clip hull type [ %9s ] [ %9s ]\n", GetClipTypeString(g_cliptype), GetClipTypeString(DEFAULT_CLIPTYPE));
  1145. #endif
  1146. Log("onlyents [ %9s ] [ %9s ]\n", g_onlyents ? "on" : "off", DEFAULT_ONLYENTS ? "on" : "off");
  1147. Log("wadtextures [ %9s ] [ %9s ]\n", g_wadtextures ? "on" : "off", DEFAULT_WADTEXTURES ? "on" : "off");
  1148. Log("skyclip [ %9s ] [ %9s ]\n", g_skyclip ? "on" : "off", DEFAULT_SKYCLIP ? "on" : "off");
  1149. Log("hullfile [ %9s ] [ %9s ]\n", g_hullfile ? g_hullfile : "None", "None");
  1150. #ifdef HLCSG_NULLIFY_INVISIBLE // KGP
  1151. Log("nullfile [ %9s ] [ %9s ]\n", g_nullfile ? g_nullfile : "None", "None");
  1152. #endif
  1153. // calc min surface area
  1154. {
  1155. char tiny_penetration[10];
  1156. char default_tiny_penetration[10];
  1157. safe_snprintf(tiny_penetration, sizeof(tiny_penetration), "%3.3f", g_tiny_threshold);
  1158. safe_snprintf(default_tiny_penetration, sizeof(default_tiny_penetration), "%3.3f", DEFAULT_TINY_THRESHOLD);
  1159. Log("min surface area [ %9s ] [ %9s ]\n", tiny_penetration, default_tiny_penetration);
  1160. }
  1161. // calc union threshold
  1162. {
  1163. char brush_union[10];
  1164. char default_brush_union[10];
  1165. safe_snprintf(brush_union, sizeof(brush_union), "%3.3f", g_BrushUnionThreshold);
  1166. safe_snprintf(default_brush_union, sizeof(default_brush_union), "%3.3f", DEFAULT_BRUSH_UNION_THRESHOLD);
  1167. Log("brush union threshold [ %9s ] [ %9s ]\n", brush_union, default_brush_union);
  1168. }
  1169. Log("\n");
  1170. }
  1171. // AJM: added in
  1172. // =====================================================================================
  1173. // CSGCleanup
  1174. // =====================================================================================
  1175. void CSGCleanup()
  1176. {
  1177. //Log("CSGCleanup\n");
  1178. #ifdef HLCSG_AUTOWAD
  1179. autowad_cleanup();
  1180. #endif
  1181. #ifdef HLCSG_WADCFG
  1182. WadCfg_cleanup();
  1183. #endif
  1184. #ifdef HLCSG_NULLIFY_TEXTURES
  1185. properties_cleanup();
  1186. #endif
  1187. FreeWadPaths();
  1188. }
  1189. // =====================================================================================
  1190. // Main
  1191. // Oh, come on.
  1192. // =====================================================================================
  1193. int main(const int argc, char** argv)
  1194. {
  1195. int i;
  1196. char name[_MAX_PATH]; // mapanme
  1197. double start, end; // start/end time log
  1198. const char* mapname_from_arg = NULL; // mapname path from passed argvar
  1199. g_Program = "hlcsg";
  1200. if (argc == 1)
  1201. Usage();
  1202. // Hard coded list of -wadinclude files, used for HINT texture brushes so lazy
  1203. // mapmakers wont cause beta testers (or possibly end users) to get a wad
  1204. // error on zhlt.wad etc
  1205. g_WadInclude.push_back("zhlt.wad");
  1206. memset(wadconfigname, 0, sizeof(wadconfigname));//AJM
  1207. // detect argv
  1208. for (i = 1; i < argc; i++)
  1209. {
  1210. if (!strcasecmp(argv[i], "-threads"))
  1211. {
  1212. if (i < argc)
  1213. {
  1214. g_numthreads = atoi(argv[++i]);
  1215. if (g_numthreads < 1)
  1216. {
  1217. Log("Expected value of at least 1 for '-threads'\n");
  1218. Usage();
  1219. }
  1220. }
  1221. else
  1222. {
  1223. Usage();
  1224. }
  1225. }
  1226. #ifdef SYSTEM_WIN32
  1227. else if (!strcasecmp(argv[i], "-estimate"))
  1228. {
  1229. g_estimate = true;
  1230. }
  1231. #endif
  1232. #ifdef SYSTEM_POSIX
  1233. else if (!strcasecmp(argv[i], "-noestimate"))
  1234. {
  1235. g_estimate = false;
  1236. }
  1237. #endif
  1238. else if (!strcasecmp(argv[i], "-dev"))
  1239. {
  1240. if (i < argc)
  1241. {
  1242. g_developer = (developer_level_t)atoi(argv[++i]);
  1243. }
  1244. else
  1245. {
  1246. Usage();
  1247. }
  1248. }
  1249. else if (!strcasecmp(argv[i], "-verbose"))
  1250. {
  1251. g_verbose = true;
  1252. }
  1253. else if (!strcasecmp(argv[i], "-noinfo"))
  1254. {
  1255. g_info = false;
  1256. }
  1257. else if (!strcasecmp(argv[i], "-chart"))
  1258. {
  1259. g_chart = true;
  1260. }
  1261. else if (!strcasecmp(argv[i], "-low"))
  1262. {
  1263. g_threadpriority = eThreadPriorityLow;
  1264. }
  1265. else if (!strcasecmp(argv[i], "-high"))
  1266. {
  1267. g_threadpriority = eThreadPriorityHigh;
  1268. }
  1269. else if (!strcasecmp(argv[i], "-nolog"))
  1270. {
  1271. g_log = false;
  1272. }
  1273. else if (!strcasecmp(argv[i], "-skyclip"))
  1274. {
  1275. g_skyclip = true;
  1276. }
  1277. else if (!strcasecmp(argv[i], "-noskyclip"))
  1278. {
  1279. g_skyclip = false;
  1280. }
  1281. else if (!strcasecmp(argv[i], "-noclip"))
  1282. {
  1283. g_noclip = true;
  1284. }
  1285. else if (!strcasecmp(argv[i], "-onlyents"))
  1286. {
  1287. g_onlyents = true;
  1288. }
  1289. #ifdef ZHLT_NULLTEX // AJM: added in -nonulltex
  1290. else if (!strcasecmp(argv[i], "-nonulltex"))
  1291. {
  1292. g_bUseNullTex = false;
  1293. }
  1294. #endif
  1295. #ifdef HLCSG_CLIPECONOMY // AJM: added in -noclipeconomy
  1296. else if (!strcasecmp(argv[i], "-noclipeconomy"))
  1297. {
  1298. g_bClipNazi = false;
  1299. }
  1300. #endif
  1301. #ifdef HLCSG_PRECISIONCLIP // KGP: added in -cliptype
  1302. else if (!strcasecmp(argv[i], "-cliptype"))
  1303. {
  1304. if (i < argc)
  1305. {
  1306. ++i;
  1307. if(!strcasecmp(argv[i],"smallest"))
  1308. { g_cliptype = clip_smallest; }
  1309. else if(!strcasecmp(argv[i],"normalized"))
  1310. { g_cliptype = clip_normalized; }
  1311. else if(!strcasecmp(argv[i],"simple"))
  1312. { g_cliptype = clip_simple; }
  1313. else if(!strcasecmp(argv[i],"precise"))
  1314. { g_cliptype = clip_precise; }
  1315. else if(!strcasecmp(argv[i],"legacy"))
  1316. { g_cliptype = clip_legacy; }
  1317. }
  1318. else
  1319. {
  1320. Log("Error: -cliptype: incorrect usage of parameter\n");
  1321. Usage();
  1322. }
  1323. }
  1324. #endif
  1325. #ifdef HLCSG_WADCFG
  1326. // AJM: added in -wadconfig
  1327. else if (!strcasecmp(argv[i], "-wadconfig"))
  1328. {
  1329. if (i < argc)
  1330. {
  1331. safe_strncpy(wadconfigname, argv[++i], MAX_WAD_CFG_NAME);
  1332. if (strlen(argv[i]) > MAX_WAD_CFG_NAME)
  1333. {
  1334. Warning("wad configuration name was truncated to %i chars", MAX_WAD_CFG_NAME);
  1335. wadconfigname[MAX_WAD_CFG_NAME] = 0;
  1336. }
  1337. }
  1338. else
  1339. {
  1340. Log("Error: -wadconfig: incorrect usage of parameter\n");
  1341. Usage();
  1342. }
  1343. }
  1344. //JK: added in -wadcfgfile
  1345. else if (!strcasecmp(argv[i], "-wadcfgfile"))
  1346. {
  1347. if (i < argc)
  1348. {
  1349. g_wadcfgfile = argv[++i];
  1350. }
  1351. else
  1352. {
  1353. Log("Error: -wadcfgfile: incorrect usage of parameter\n");
  1354. Usage();
  1355. }
  1356. }
  1357. #endif
  1358. #ifdef HLCSG_NULLIFY_INVISIBLE
  1359. else if (!strcasecmp(argv[i], "-nullfile"))
  1360. {
  1361. if (i < argc)
  1362. {
  1363. g_nullfile = argv[++i];
  1364. }
  1365. else
  1366. {
  1367. Log("Error: -nullfile: expected path to null ent file following parameter\n");
  1368. Usage();
  1369. }
  1370. }
  1371. #endif
  1372. #ifdef HLCSG_AUTOWAD // AJM
  1373. else if (!strcasecmp(argv[i], "-wadautodetect"))
  1374. {
  1375. g_bWadAutoDetect = true;
  1376. }
  1377. #endif
  1378. #ifdef ZHLT_DETAIL // AJM
  1379. else if (!strcasecmp(argv[i], "-nodetail"))
  1380. {
  1381. g_bDetailBrushes = false;
  1382. }
  1383. #endif
  1384. #ifdef ZHLT_PROGRESSFILE // AJM
  1385. else if (!strcasecmp(argv[i], "-progressfile"))
  1386. {
  1387. if (i < argc)
  1388. {
  1389. g_progressfile = argv[++i];
  1390. }
  1391. else
  1392. {
  1393. Log("Error: -progressfile: expected path to progress file following parameter\n");
  1394. Usage();
  1395. }
  1396. }
  1397. #endif
  1398. else if (!strcasecmp(argv[i], "-nowadtextures"))
  1399. {
  1400. g_wadtextures = false;
  1401. }
  1402. else if (!strcasecmp(argv[i], "-wadinclude"))
  1403. {
  1404. if (i < argc)
  1405. {
  1406. g_WadInclude.push_back(argv[++i]);
  1407. }
  1408. else
  1409. {
  1410. Usage();
  1411. }
  1412. }
  1413. else if (!strcasecmp(argv[i], "-texdata"))
  1414. {
  1415. if (i < argc)
  1416. {
  1417. int x = atoi(argv[++i]) * 1024;
  1418. if (x > g_max_map_miptex)
  1419. {
  1420. g_max_map_miptex = x;
  1421. }
  1422. }
  1423. else
  1424. {
  1425. Usage();
  1426. }
  1427. }
  1428. else if (!strcasecmp(argv[i], "-lightdata"))
  1429. {
  1430. if (i < argc)
  1431. {
  1432. int x = atoi(argv[++i]) * 1024;
  1433. if (x > g_max_map_lightdata)
  1434. {
  1435. g_max_map_lightdata = x;
  1436. }
  1437. }
  1438. else
  1439. {
  1440. Usage();
  1441. }
  1442. }
  1443. else if (!strcasecmp(argv[i], "-brushunion"))
  1444. {
  1445. if (i < argc)
  1446. {
  1447. g_BrushUnionThreshold = (float)atof(argv[++i]);
  1448. }
  1449. else
  1450. {
  1451. Usage();
  1452. }
  1453. }
  1454. else if (!strcasecmp(argv[i], "-tiny"))
  1455. {
  1456. if (i < argc)
  1457. {
  1458. g_tiny_threshold = (float)atof(argv[++i]);
  1459. }
  1460. else
  1461. {
  1462. Usage();
  1463. }
  1464. }
  1465. else if (!strcasecmp(argv[i], "-hullfile"))
  1466. {
  1467. if (i < argc)
  1468. {
  1469. g_hullfile = argv[++i];
  1470. }
  1471. else
  1472. {
  1473. Usage();
  1474. }
  1475. }
  1476. // SILENCER -->
  1477. else if (!strcasecmp(argv[i], "-noconcolors"))
  1478. {
  1479. g_noConColors = true;
  1480. }
  1481. // <-- SILENCER
  1482. else if (argv[i][0] == '-')
  1483. {
  1484. Log("Unknown option \"%s\"\n", argv[i]);
  1485. Usage();
  1486. }
  1487. else if (!mapname_from_arg)
  1488. {
  1489. mapname_from_arg = argv[i];
  1490. }
  1491. else
  1492. {
  1493. Log("Unknown option \"%s\"\n", argv[i]);
  1494. Usage();
  1495. }
  1496. }
  1497. // no mapfile?
  1498. if (!mapname_from_arg)
  1499. {
  1500. // what a shame.
  1501. Log("No mapfile specified\n");
  1502. Usage();
  1503. }
  1504. // handle mapname
  1505. safe_strncpy(g_Mapname, mapname_from_arg, _MAX_PATH);
  1506. FlipSlashes(g_Mapname);
  1507. StripExtension(g_Mapname);
  1508. // onlyents
  1509. if (!g_onlyents)
  1510. ResetTmpFiles();
  1511. // other stuff
  1512. ResetErrorLog();
  1513. ResetLog();
  1514. OpenLog(g_clientid);
  1515. atexit(CloseLog);
  1516. LogStart(argc, argv);
  1517. atexit(CSGCleanup); // AJM
  1518. dtexdata_init();
  1519. atexit(dtexdata_free);
  1520. // START CSG
  1521. // AJM: re-arranged some stuff up here so that the mapfile is loaded
  1522. // before settings are finalised and printed out, so that the info_compile_parameters
  1523. // entity can be dealt with effectively
  1524. start = I_FloatTime();
  1525. LoadHullfile(g_hullfile); // if the user specified a hull file, load it now
  1526. #ifdef HLCSG_NULLIFY_INVISIBLE
  1527. if(g_bUseNullTex)
  1528. { properties_initialize(g_nullfile); }
  1529. #endif
  1530. safe_strncpy(name, mapname_from_arg, _MAX_PATH); // make a copy of the nap name
  1531. DefaultExtension(name, ".map"); // might be .reg
  1532. LoadMapFile(name);
  1533. ThreadSetDefault();
  1534. ThreadSetPriority(g_threadpriority);
  1535. Settings();
  1536. #ifdef HLCSG_WADCFG // AJM
  1537. // figure out what to do with the texture settings
  1538. if (wadconfigname[0]) // custom wad configuations will take precedence
  1539. {
  1540. LoadWadConfigFile();
  1541. ProcessWadConfiguration();
  1542. }
  1543. else
  1544. {
  1545. Log("Using mapfile wad configuration\n");
  1546. }
  1547. if (!g_bWadConfigsLoaded) // dont try and override wad.cfg
  1548. #endif
  1549. {
  1550. GetUsedWads();
  1551. }
  1552. #ifdef HLCSG_AUTOWAD
  1553. if (g_bWadAutoDetect)
  1554. {
  1555. Log("Wadfiles not in use by the map will be excluded\n");
  1556. }
  1557. #endif
  1558. DumpWadinclude();
  1559. Log("\n");
  1560. // if onlyents, just grab the entites and resave
  1561. if (g_onlyents)
  1562. {
  1563. char out[_MAX_PATH];
  1564. safe_snprintf(out, _MAX_PATH, "%s.bsp", g_Mapname);
  1565. LoadBSPFile(out);
  1566. LoadWadincludeFile(g_Mapname);
  1567. HandleWadinclude();
  1568. // Write it all back out again.
  1569. if (g_chart)
  1570. {
  1571. PrintBSPFileSizes();
  1572. }
  1573. WriteBSP(g_Mapname);
  1574. end = I_FloatTime();
  1575. LogTimeElapsed(end - start);
  1576. return 0;
  1577. }
  1578. else
  1579. {
  1580. SaveWadincludeFile(g_Mapname);
  1581. }
  1582. #ifdef HLCSG_CLIPECONOMY // AJM
  1583. CheckForNoClip();
  1584. #endif
  1585. // createbrush
  1586. NamedRunThreadsOnIndividual(g_nummapbrushes, g_estimate, CreateBrush);
  1587. CheckFatal();
  1588. #ifdef HLCSG_PRECISIONCLIP // KGP - drop TEX_BEVEL flag
  1589. FixBevelTextures();
  1590. #endif
  1591. // boundworld
  1592. BoundWorld();
  1593. Verbose("%5i map planes\n", g_nummapplanes);
  1594. // Set model centers
  1595. NamedRunThreadsOnIndividual(g_numentities, g_estimate, SetModelCenters);
  1596. // Calc brush unions
  1597. if ((g_BrushUnionThreshold > 0.0) && (g_BrushUnionThreshold <= 100.0))
  1598. {
  1599. NamedRunThreadsOnIndividual(g_nummapbrushes, g_estimate, CalculateBrushUnions);
  1600. }
  1601. // open hull files
  1602. for (i = 0; i < NUM_HULLS; i++)
  1603. {
  1604. char name[_MAX_PATH];
  1605. safe_snprintf(name, _MAX_PATH, "%s.p%i", g_Mapname, i);
  1606. out[i] = fopen(name, "w");
  1607. if (!out[i])
  1608. Error("Couldn't open %s", name);
  1609. }
  1610. ProcessModels();
  1611. Verbose("%5i csg faces\n", c_csgfaces);
  1612. Verbose("%5i used faces\n", c_outfaces);
  1613. Verbose("%5i tiny faces\n", c_tiny);
  1614. Verbose("%5i tiny clips\n", c_tiny_clip);
  1615. // close hull files
  1616. for (i = 0; i < NUM_HULLS; i++)
  1617. fclose(out[i]);
  1618. EmitPlanes();
  1619. if (g_chart)
  1620. PrintBSPFileSizes();
  1621. WriteBSP(g_Mapname);
  1622. // AJM: debug
  1623. #if 0
  1624. Log("\n---------------------------------------\n"
  1625. "Map Plane Usage:\n"
  1626. " # normal origin dist type\n"
  1627. " ( x, y, z) ( x, y, z) ( )\n"
  1628. );
  1629. for (i = 0; i < g_nummapplanes; i++)
  1630. {
  1631. plane_t* p = &g_mapplanes[i];
  1632. Log(
  1633. "%3i (%4.0f, %4.0f, %4.0f) (%4.0f, %4.0f, %4.0f) (%5.0f) %i\n",
  1634. i,
  1635. p->normal[1], p->normal[2], p->normal[3],
  1636. p->origin[1], p->origin[2], p->origin[3],
  1637. p->dist,
  1638. p->type
  1639. );
  1640. }
  1641. Log("---------------------------------------\n\n");
  1642. #endif
  1643. // elapsed time
  1644. end = I_FloatTime();
  1645. LogTimeElapsed(end - start);
  1646. return 0;
  1647. }