//#pragma warning(disable: 4018) // '<' : signed/unsigned mismatch /* CONSTRUCTIVE SOLID GEOMETRY -aka- C S G Code based on original code from Valve Software, Modified by Sean "Zoner" Cavanaugh (seanc@gearboxsoftware.com) with permission. Modified by Tony "Merl" Moore (merlinis@bigpond.net.au) [AJM] */ #include "csg.h" #ifdef SYSTEM_WIN32 #define WIN32_LEAN_AND_MEAN #include //--vluzacn #endif /* NOTES - check map size for +/- 4k limit at load time - allow for multiple wad.cfg configurations per compile */ static FILE* out[NUM_HULLS]; // pointer to each of the hull out files (.p0, .p1, ect.) #ifdef HLCSG_VIEWSURFACE static FILE* out_view[NUM_HULLS]; #endif #ifdef ZHLT_DETAILBRUSH static FILE* out_detailbrush[NUM_HULLS]; #endif static int c_tiny; static int c_tiny_clip; static int c_outfaces; static int c_csgfaces; BoundingBox world_bounds; #ifndef HLCSG_WADCFG_NEW #ifdef HLCSG_WADCFG char wadconfigname[MAX_WAD_CFG_NAME]; #endif #endif vec_t g_tiny_threshold = DEFAULT_TINY_THRESHOLD; bool g_noclip = DEFAULT_NOCLIP; // no clipping hull "-noclip" bool g_onlyents = DEFAULT_ONLYENTS; // onlyents mode "-onlyents" bool g_wadtextures = DEFAULT_WADTEXTURES; // "-nowadtextures" bool g_chart = DEFAULT_CHART; // show chart "-chart" bool g_skyclip = DEFAULT_SKYCLIP; // no sky clipping "-noskyclip" bool g_estimate = DEFAULT_ESTIMATE; // progress estimates "-estimate" bool g_info = DEFAULT_INFO; // "-info" ? const char* g_hullfile = NULL; // external hullfile "-hullfie sdfsd" #ifdef HLCSG_WADCFG_NEW const char* g_wadcfgfile = NULL; const char* g_wadconfigname = NULL; #endif #ifdef ZHLT_NULLTEX // AJM bool g_bUseNullTex = DEFAULT_NULLTEX; // "-nonulltex" #endif #ifdef HLCSG_PRECISIONCLIP // KGP cliptype g_cliptype = DEFAULT_CLIPTYPE; // "-cliptype " #endif #ifdef HLCSG_NULLIFY_INVISIBLE const char* g_nullfile = NULL; #endif #ifdef HLCSG_CLIPECONOMY // AJM bool g_bClipNazi = DEFAULT_CLIPNAZI; // "-noclipeconomy" #endif #ifdef HLCSG_AUTOWAD // AJM bool g_bWadAutoDetect = DEFAULT_WADAUTODETECT; // "-wadautodetect" #endif #ifdef ZHLT_DETAIL // AJM bool g_bDetailBrushes = DEFAULT_DETAIL; // "-detail" #endif #ifdef ZHLT_PROGRESSFILE // AJM char* g_progressfile = DEFAULT_PROGRESSFILE; // "-progressfile path" #endif #ifdef HLCSG_SCALESIZE vec_t g_scalesize = DEFAULT_SCALESIZE; #endif #ifdef HLCSG_KEEPLOG bool g_resetlog = DEFAULT_RESETLOG; #endif #ifdef HLCSG_OPTIMIZELIGHTENTITY bool g_nolightopt = DEFAULT_NOLIGHTOPT; #endif #ifdef HLCSG_GAMETEXTMESSAGE_UTF8 bool g_noutf8 = DEFAULT_NOUTF8; #endif #ifdef HLCSG_NULLIFYAAATRIGGER bool g_nullifytrigger = DEFAULT_NULLIFYTRIGGER; #endif #ifdef HLCSG_VIEWSURFACE bool g_viewsurface = false; #endif #ifdef ZHLT_INFO_COMPILE_PARAMETERS // ===================================================================================== // GetParamsFromEnt // parses entity keyvalues for setting information // ===================================================================================== void GetParamsFromEnt(entity_t* mapent) { int iTmp; char szTmp[256]; Log("\nCompile Settings detected from info_compile_parameters entity\n"); // verbose(choices) : "Verbose compile messages" : 0 = [ 0 : "Off" 1 : "On" ] iTmp = IntForKey(mapent, "verbose"); if (iTmp == 1) { g_verbose = true; } else if (iTmp == 0) { g_verbose = false; } Log("%30s [ %-9s ]\n", "Compile Option", "setting"); Log("%30s [ %-9s ]\n", "Verbose Compile Messages", g_verbose ? "on" : "off"); // estimate(choices) :"Estimate Compile Times?" : 0 = [ 0: "Yes" 1: "No" ] if (IntForKey(mapent, "estimate")) { g_estimate = true; } else { g_estimate = false; } Log("%30s [ %-9s ]\n", "Estimate Compile Times", g_estimate ? "on" : "off"); // priority(choices) : "Priority Level" : 0 = [ 0 : "Normal" 1 : "High" -1 : "Low" ] if (!strcmp(ValueForKey(mapent, "priority"), "1")) { g_threadpriority = eThreadPriorityHigh; Log("%30s [ %-9s ]\n", "Thread Priority", "high"); } else if (!strcmp(ValueForKey(mapent, "priority"), "-1")) { g_threadpriority = eThreadPriorityLow; Log("%30s [ %-9s ]\n", "Thread Priority", "low"); } // texdata(string) : "Texture Data Memory" : "4096" iTmp = IntForKey(mapent, "texdata") * 1024; if (iTmp > g_max_map_miptex) { g_max_map_miptex = iTmp; } sprintf_s(szTmp, "%i", g_max_map_miptex); Log("%30s [ %-9s ]\n", "Texture Data Memory", szTmp); // hullfile(string) : "Custom Hullfile" if (ValueForKey(mapent, "hullfile")) { g_hullfile = ValueForKey(mapent, "hullfile"); Log("%30s [ %-9s ]\n", "Custom Hullfile", g_hullfile); } #ifdef HLCSG_AUTOWAD // wadautodetect(choices) : "Wad Auto Detect" : 0 = [ 0 : "Off" 1 : "On" ] if (!strcmp(ValueForKey(mapent, "wadautodetect"), "1")) { g_bWadAutoDetect = true; } else { g_bWadAutoDetect = false; } Log("%30s [ %-9s ]\n", "Wad Auto Detect", g_bWadAutoDetect ? "on" : "off"); #endif #ifndef HLCSG_WADCFG_NEW #ifdef HLCSG_WADCFG // wadconfig(string) : "Custom Wad Configuration" : "" if (strlen(ValueForKey(mapent, "wadconfig")) > 0) { safe_strncpy(wadconfigname, ValueForKey(mapent, "wadconfig"), MAX_WAD_CFG_NAME); Log("%30s [ %-9s ]\n", "Custom Wad Configuration", wadconfigname); } #endif #endif #ifdef HLCSG_WADCFG_NEW // wadconfig(string) : "Custom Wad Configuration" : "" if (*ValueForKey(mapent, "wadconfig")) { g_wadconfigname = _strdup (ValueForKey(mapent, "wadconfig")); Log("%30s [ %-9s ]\n", "Custom Wad Configuration Name", g_wadconfigname); } // wadcfgfile(string) : "Custom Wad Configuration File" : "" if (*ValueForKey(mapent, "wadcfgfile")) { g_wadcfgfile = _strdup (ValueForKey(mapent, "wadcfgfile")); Log("%30s [ %-9s ]\n", "Custom Wad Configuration File", g_wadcfgfile); } #endif #ifdef HLCSG_CLIPECONOMY // noclipeconomy(choices) : "Strip Uneeded Clipnodes?" : 1 = [ 1 : "Yes" 0 : "No" ] iTmp = IntForKey(mapent, "noclipeconomy"); if (iTmp == 1) { g_bClipNazi = true; } else if (iTmp == 0) { g_bClipNazi = false; } Log("%30s [ %-9s ]\n", "Clipnode Economy Mode", g_bClipNazi ? "on" : "off"); #endif /* hlcsg(choices) : "HLCSG" : 1 = [ 1 : "Normal" 2 : "Onlyents" 0 : "Off" ] */ iTmp = IntForKey(mapent, "hlcsg"); g_onlyents = false; if (iTmp == 2) { g_onlyents = true; } else if (iTmp == 0) { Fatal(assume_TOOL_CANCEL, "%s was set to \"Off\" (0) in info_compile_parameters entity, execution cancelled", g_Program); CheckFatal(); } Log("%30s [ %-9s ]\n", "Onlyents", g_onlyents ? "on" : "off"); /* nocliphull(choices) : "Generate clipping hulls" : 0 = [ 0 : "Yes" 1 : "No" ] */ iTmp = IntForKey(mapent, "nocliphull"); if (iTmp == 1) { g_noclip = true; } else { g_noclip = false; } Log("%30s [ %-9s ]\n", "Clipping Hull Generation", g_noclip ? "off" : "on"); #ifdef HLCSG_PRECISIONCLIP // cliptype(choices) : "Clip Hull Type" : 4 = [ 0 : "Smallest" 1 : "Normalized" 2: "Simple" 3 : "Precise" 4 : "Legacy" ] iTmp = IntForKey(mapent, "cliptype"); switch(iTmp) { case 0: g_cliptype = clip_smallest; break; case 1: g_cliptype = clip_normalized; break; case 2: g_cliptype = clip_simple; break; case 3: g_cliptype = clip_precise; break; default: g_cliptype = clip_legacy; break; } Log("%30s [ %-9s ]\n", "Clip Hull Type", GetClipTypeString(g_cliptype)); #endif /* noskyclip(choices) : "No Sky Clip" : 0 = [ 1 : "On" 0 : "Off" ] */ iTmp = IntForKey(mapent, "noskyclip"); if (iTmp == 1) { g_skyclip = false; } else { g_skyclip = true; } Log("%30s [ %-9s ]\n", "Sky brush clip generation", g_skyclip ? "on" : "off"); /////////////// Log("\n"); } #endif #ifndef HLCSG_CUSTOMHULL #ifdef HLCSG_PRECISIONCLIP // ===================================================================================== // FixBevelTextures // ===================================================================================== void FixBevelTextures() { for(int counter = 0; counter < g_numtexinfo; counter++) { if(g_texinfo[counter].flags & TEX_BEVEL) { g_texinfo[counter].flags &= ~TEX_BEVEL; } } } #endif #endif // ===================================================================================== // NewFaceFromFace // Duplicates the non point information of a face, used by SplitFace // ===================================================================================== bface_t* NewFaceFromFace(const bface_t* const in) { bface_t* newf; newf = (bface_t*)Alloc(sizeof(bface_t)); newf->contents = in->contents; newf->texinfo = in->texinfo; newf->planenum = in->planenum; newf->plane = in->plane; #ifdef HLCSG_EMPTYBRUSH newf->backcontents = in->backcontents; #endif return newf; } // ===================================================================================== // FreeFace // ===================================================================================== void FreeFace(bface_t* f) { delete f->w; Free(f); } #ifndef HLCSG_NOFAKESPLITS // ===================================================================================== // ClipFace // Clips a faces by a plane, returning the fragment on the backside and adding any // fragment to the outside. // Faces exactly on the plane will stay inside unless overdrawn by later brush. // Frontside is the side of the plane that holds the outside list. // Precedence is necesary to handle overlapping coplanar faces. #define SPLIT_EPSILON 0.3 // ===================================================================================== static bface_t* ClipFace(bface_t* f, bface_t** outside, const int splitplane, const bool precedence) { bface_t* front; // clip face Winding* fw; // forward wind Winding* bw; // back wind plane_t* split; // plane to clip on // handle exact plane matches special if (f->planenum == (splitplane ^ 1)) return f; // opposite side, so put on inside list if (f->planenum == splitplane) // coplanar { // this fragment will go to the inside, because // the earlier one was clipped to the outside if (precedence) return f; f->next = *outside; *outside = f; return NULL; } split = &g_mapplanes[splitplane]; f->w->Clip(split->normal, split->dist, &fw, &bw); if (!fw) { delete bw; return f; } else if (!bw) { delete fw; f->next = *outside; *outside = f; return NULL; } else { delete f->w; front = NewFaceFromFace(f); front->w = fw; fw->getBounds(front->bounds); front->next = *outside; *outside = front; f->w = bw; bw->getBounds(f->bounds); return f; } } #endif // ===================================================================================== // WriteFace // ===================================================================================== void WriteFace(const int hull, const bface_t* const f #ifdef ZHLT_DETAILBRUSH , int detaillevel #endif ) { unsigned int i; Winding* w; ThreadLock(); if (!hull) c_csgfaces++; // .p0 format w = f->w; // plane summary #ifdef ZHLT_DETAILBRUSH fprintf (out[hull], "%i %i %i %i %u\n", detaillevel, f->planenum, f->texinfo, f->contents, w->m_NumPoints); #else fprintf(out[hull], "%i %i %i %u\n", f->planenum, f->texinfo, f->contents, w->m_NumPoints); #endif // for each of the points on the face for (i = 0; i < w->m_NumPoints; i++) { // write the co-ords #ifdef HLCSG_PRICISION_FIX fprintf(out[hull], "%5.8f %5.8f %5.8f\n", w->m_Points[i][0], w->m_Points[i][1], w->m_Points[i][2]); #else 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]); #endif } // put in an extra line break fprintf(out[hull], "\n"); #ifdef HLCSG_VIEWSURFACE if (g_viewsurface) { static bool side = false; side = !side; if (side) { vec3_t center, center2; w->getCenter (center); VectorAdd (center, f->plane->normal, center2); fprintf (out_view[hull], "%5.2f %5.2f %5.2f\n", center2[0], center2[1], center2[2]); for (i = 0; i < w->m_NumPoints; i++) { vec_t *p1, *p2; p1 = w->m_Points[i]; p2 = w->m_Points[(i+1)%w->m_NumPoints]; fprintf (out_view[hull], "%5.2f %5.2f %5.2f\n", center[0], center[1], center[2]); fprintf (out_view[hull], "%5.2f %5.2f %5.2f\n", p1[0], p1[1], p1[2]); fprintf (out_view[hull], "%5.2f %5.2f %5.2f\n", p2[0], p2[1], p2[2]); } fprintf (out_view[hull], "%5.2f %5.2f %5.2f\n", center[0], center[1], center[2]); fprintf (out_view[hull], "%5.2f %5.2f %5.2f\n", center2[0], center2[1], center2[2]); } } #endif ThreadUnlock(); } #ifdef ZHLT_DETAILBRUSH void WriteDetailBrush (int hull, const bface_t *faces) { ThreadLock (); fprintf (out_detailbrush[hull], "0\n"); for (const bface_t *f = faces; f; f = f->next) { Winding *w = f->w; fprintf (out_detailbrush[hull], "%i %u\n", f->planenum, w->m_NumPoints); for (int i = 0; i < w->m_NumPoints; i++) { fprintf (out_detailbrush[hull], "%5.8f %5.8f %5.8f\n", w->m_Points[i][0], w->m_Points[i][1], w->m_Points[i][2]); } } fprintf (out_detailbrush[hull], "-1 -1\n"); ThreadUnlock (); } #endif // ===================================================================================== // SaveOutside // The faces remaining on the outside list are final polygons. Write them to the // output file. // Passable contents (water, lava, etc) will generate a mirrored copy of the face // to be seen from the inside. // ===================================================================================== static void SaveOutside(const brush_t* const b, const int hull, bface_t* outside, const int mirrorcontents) { bface_t* f; bface_t* f2; bface_t* next; int i; vec3_t temp; for (f = outside; f; f = next) { next = f->next; #ifdef HLCSG_EMPTYBRUSH int frontcontents, backcontents; int texinfo = f->texinfo; const char *texname = GetTextureByNumber_CSG (texinfo); frontcontents = f->contents; if (mirrorcontents == CONTENTS_TOEMPTY) { backcontents = f->backcontents; } else { backcontents = mirrorcontents; } if (frontcontents == CONTENTS_TOEMPTY) { frontcontents = CONTENTS_EMPTY; } if (backcontents == CONTENTS_TOEMPTY) { backcontents = CONTENTS_EMPTY; } bool frontnull, backnull; frontnull = false; backnull = false; if (mirrorcontents == CONTENTS_TOEMPTY) { if (strncasecmp (texname, "SKIP", 4) && strncasecmp (texname, "HINT", 4) #ifdef HLCSG_HLBSP_SOLIDHINT && strncasecmp (texname, "SOLIDHINT", 9) #endif ) // SKIP and HINT are special textures for hlbsp { backnull = true; } } #ifdef HLCSG_HLBSP_SOLIDHINT if (!strncasecmp (texname, "SOLIDHINT", 9)) { if (frontcontents != backcontents) { frontnull = backnull = true; // not discardable, so remove "SOLIDHINT" texture name and behave like NULL } } #endif #ifdef HLCSG_WATERBACKFACE_FIX if (b->entitynum != 0 && !strncasecmp (texname, "!", 1)) { backnull = true; // strip water face on one side } #endif #endif #ifdef HLCSG_EMPTYBRUSH f->contents = frontcontents; f->texinfo = frontnull? -1: texinfo; #endif if (f->w->getArea() < g_tiny_threshold) { c_tiny++; Verbose("Entity %i, Brush %i: tiny fragment\n", #ifdef HLCSG_COUNT_NEW b->originalentitynum, b->originalbrushnum #else b->entitynum, b->brushnum #endif ); continue; } // count unique faces if (!hull) { for (f2 = b->hulls[hull].faces; f2; f2 = f2->next) { if (f2->planenum == f->planenum) { if (!f2->used) { f2->used = true; c_outfaces++; } break; } } } #ifdef HLCSG_WARNBADTEXINFO // check the texture alignment of this face if (!hull) { int texinfo = f->texinfo; const char *texname = GetTextureByNumber_CSG (texinfo); texinfo_t *tex = &g_texinfo[texinfo]; if (texinfo != -1 // nullified textures (NULL, BEVEL, aaatrigger, etc.) && !(tex->flags & TEX_SPECIAL) // sky && strncasecmp (texname, "SKIP", 4) && strncasecmp (texname, "HINT", 4) // HINT and SKIP will be nullified only after hlbsp #ifdef HLCSG_HLBSP_SOLIDHINT && strncasecmp (texname, "SOLIDHINT", 9) #endif ) { // check for "Malformed face (%d) normal" vec3_t texnormal; CrossProduct (tex->vecs[1], tex->vecs[0], texnormal); VectorNormalize (texnormal); if (fabs (DotProduct (texnormal, f->plane->normal)) <= NORMAL_EPSILON) { Warning ("Entity %i, Brush %i: Malformed texture alignment (texture %s): Texture axis perpendicular to face.", #ifdef HLCSG_COUNT_NEW b->originalentitynum, b->originalbrushnum, #else b->entitynum, b->brushnum, #endif texname ); } // check for "Bad surface extents" bool bad; int i; int j; vec_t val; bad = false; for (i = 0; i < f->w->m_NumPoints; i++) { for (j = 0; j < 2; j++) { val = DotProduct (f->w->m_Points[i], tex->vecs[j]) + tex->vecs[j][3]; if (val < -99999 || val > 999999) { bad = true; } } } if (bad) { Warning ("Entity %i, Brush %i: Malformed texture alignment (texture %s): Bad surface extents.", #ifdef HLCSG_COUNT_NEW b->originalentitynum, b->originalbrushnum, #else b->entitynum, b->brushnum, #endif texname ); } } } #endif WriteFace(hull, f #ifdef ZHLT_DETAILBRUSH , #ifdef ZHLT_CLIPNODEDETAILLEVEL (hull? b->clipnodedetaillevel: b->detaillevel) #else b->detaillevel #endif #endif ); // if (mirrorcontents != CONTENTS_SOLID) { f->planenum ^= 1; f->plane = &g_mapplanes[f->planenum]; #ifdef HLCSG_EMPTYBRUSH f->contents = backcontents; f->texinfo = backnull? -1: texinfo; #else f->contents = mirrorcontents; #endif // swap point orders for (i = 0; i < f->w->m_NumPoints / 2; i++) // add points backwards { VectorCopy(f->w->m_Points[i], temp); VectorCopy(f->w->m_Points[f->w->m_NumPoints - 1 - i], f->w->m_Points[i]); VectorCopy(temp, f->w->m_Points[f->w->m_NumPoints - 1 - i]); } WriteFace(hull, f #ifdef ZHLT_DETAILBRUSH , #ifdef ZHLT_CLIPNODEDETAILLEVEL (hull? b->clipnodedetaillevel: b->detaillevel) #else b->detaillevel #endif #endif ); } FreeFace(f); } } // ===================================================================================== // CopyFace // ===================================================================================== bface_t* CopyFace(const bface_t* const f) { bface_t* n; n = NewFaceFromFace(f); n->w = f->w->Copy(); n->bounds = f->bounds; return n; } // ===================================================================================== // CopyFaceList // ===================================================================================== bface_t* CopyFaceList(bface_t* f) { bface_t* head; bface_t* n; if (f) { head = CopyFace(f); n = head; f = f->next; while (f) { n->next = CopyFace(f); n = n->next; f = f->next; } return head; } else { return NULL; } } // ===================================================================================== // FreeFaceList // ===================================================================================== void FreeFaceList(bface_t* f) { if (f) { if (f->next) { FreeFaceList(f->next); } FreeFace(f); } } // ===================================================================================== // CopyFacesToOutside // Make a copy of all the faces of the brush, so they can be chewed up by other // brushes. // All of the faces start on the outside list. // As other brushes take bites out of the faces, the fragments are moved to the // inside list, so they can be freed when they are determined to be completely // enclosed in solid. // ===================================================================================== static bface_t* CopyFacesToOutside(brushhull_t* bh) { bface_t* f; bface_t* newf; bface_t* outside; outside = NULL; for (f = bh->faces; f; f = f->next) { newf = CopyFace(f); newf->w->getBounds(newf->bounds); newf->next = outside; outside = newf; } return outside; } // ===================================================================================== // CSGBrush // ===================================================================================== #ifdef ZHLT_DETAILBRUSH extern const char *ContentsToString (const contents_t type); #endif static void CSGBrush(int brushnum) { int hull; brush_t* b1; brush_t* b2; brushhull_t* bh1; brushhull_t* bh2; int bn; bool overwrite; bface_t* f; bface_t* f2; bface_t* next; #ifndef HLCSG_NOFAKESPLITS bface_t* fcopy; #endif bface_t* outside; #ifndef HLCSG_NOFAKESPLITS bface_t* oldoutside; #endif entity_t* e; vec_t area; // get entity and brush info from the given brushnum that we can work with b1 = &g_mapbrushes[brushnum]; e = &g_entities[b1->entitynum]; // for each of the hulls for (hull = 0; hull < NUM_HULLS; hull++) { bh1 = &b1->hulls[hull]; #ifdef ZHLT_DETAILBRUSH if (bh1->faces && #ifdef ZHLT_CLIPNODEDETAILLEVEL (hull? b1->clipnodedetaillevel: b1->detaillevel) #else b1->detaillevel #endif ) { switch (b1->contents) { case CONTENTS_ORIGIN: #ifdef HLCSG_HLBSP_CUSTOMBOUNDINGBOX case CONTENTS_BOUNDINGBOX: #endif case CONTENTS_HINT: #ifdef HLCSG_EMPTYBRUSH case CONTENTS_TOEMPTY: #endif break; default: Error ("Entity %i, Brush %i: %s brushes not allowed in detail\n", #ifdef HLCSG_COUNT_NEW b1->originalentitynum, b1->originalbrushnum, #else b1->entitynum, b1->brushnum, #endif ContentsToString((contents_t)b1->contents)); break; case CONTENTS_SOLID: WriteDetailBrush (hull, bh1->faces); break; } } #endif // set outside to a copy of the brush's faces outside = CopyFacesToOutside(bh1); overwrite = false; #ifdef HLCSG_EMPTYBRUSH if (b1->contents == CONTENTS_TOEMPTY) { for (f = outside; f; f = f->next) { f->contents = CONTENTS_TOEMPTY; f->backcontents = CONTENTS_TOEMPTY; } } #endif // for each brush in entity e for (bn = 0; bn < e->numbrushes; bn++) { // see if b2 needs to clip a chunk out of b1 #ifdef HLCSG_CSGBrush_BRUSHNUM_FIX if (e->firstbrush + bn == brushnum) { continue; } overwrite = e->firstbrush + bn > brushnum; #else if (bn == brushnum) { overwrite = true; // later brushes now overwrite continue; } #endif b2 = &g_mapbrushes[e->firstbrush + bn]; bh2 = &b2->hulls[hull]; #ifdef HLCSG_EMPTYBRUSH if (b2->contents == CONTENTS_TOEMPTY) continue; #endif #ifdef ZHLT_DETAILBRUSH if ( #ifdef ZHLT_CLIPNODEDETAILLEVEL (hull? (b2->clipnodedetaillevel - 0 > b1->clipnodedetaillevel + 0): (b2->detaillevel - b2->chopdown > b1->detaillevel + b1->chopup)) #else b2->detaillevel - b2->chopdown > b1->detaillevel + b1->chopup #endif ) continue; // you can't chop if (b2->contents == b1->contents && #ifdef ZHLT_CLIPNODEDETAILLEVEL (hull? (b2->clipnodedetaillevel != b1->clipnodedetaillevel): (b2->detaillevel != b1->detaillevel)) #else b2->detaillevel != b1->detaillevel #endif ) { overwrite = #ifdef ZHLT_CLIPNODEDETAILLEVEL (hull? (b2->clipnodedetaillevel < b1->clipnodedetaillevel): (b2->detaillevel < b1->detaillevel)) #else b2->detaillevel < b1->detaillevel #endif ; } #endif #ifdef HLCSG_COPLANARPRIORITY if (b2->contents == b1->contents && hull == 0 && b2->detaillevel == b1->detaillevel && b2->coplanarpriority != b1->coplanarpriority) { overwrite = b2->coplanarpriority > b1->coplanarpriority; } #endif if (!bh2->faces) continue; // brush isn't in this hull // check brush bounding box first // TODO: use boundingbox method instead if (bh1->bounds.testDisjoint(bh2->bounds)) { continue; } // divide faces by the planes of the b2 to find which // fragments are inside f = outside; outside = NULL; for (; f; f = next) { next = f->next; // check face bounding box first if (bh2->bounds.testDisjoint(f->bounds)) { // this face doesn't intersect brush2's bbox f->next = outside; outside = f; continue; } #ifdef ZHLT_DETAILBRUSH if ( #ifdef ZHLT_CLIPNODEDETAILLEVEL (hull? (b2->clipnodedetaillevel > b1->clipnodedetaillevel): (b2->detaillevel > b1->detaillevel)) #else b2->detaillevel > b1->detaillevel #endif ) { const char *texname = GetTextureByNumber_CSG (f->texinfo); if (f->texinfo == -1 || !strncasecmp (texname, "SKIP", 4) || !strncasecmp (texname, "HINT", 4) #ifdef HLCSG_HLBSP_SOLIDHINT || !strncasecmp (texname, "SOLIDHINT", 9) #endif ) { // should not nullify the fragment inside detail brush f->next = outside; outside = f; continue; } } #endif #ifndef HLCSG_NOFAKESPLITS oldoutside = outside; fcopy = CopyFace(f); // save to avoid fake splits #endif // throw pieces on the front sides of the planes // into the outside list, return the remains on the inside #ifdef HLCSG_NOFAKESPLITS // find the fragment inside brush2 Winding *w = new Winding (*f->w); for (f2 = bh2->faces; f2; f2 = f2->next) { if (f->planenum == f2->planenum) { if (!overwrite) { // face plane is outside brush2 w->m_NumPoints = 0; break; } else { continue; } } if (f->planenum == (f2->planenum ^ 1)) { continue; } Winding *fw; Winding *bw; w->Clip (f2->plane->normal, f2->plane->dist, &fw, &bw); if (fw) { delete fw; } if (bw) { delete w; w = bw; } else { w->m_NumPoints = 0; break; } } // do real split if (w->m_NumPoints) { for (f2 = bh2->faces; f2; f2 = f2->next) { if (f->planenum == f2->planenum || f->planenum == (f2->planenum ^ 1)) { continue; } int valid = 0; int x; for (x = 0; x < w->m_NumPoints; x++) { vec_t dist = DotProduct (w->m_Points[x], f2->plane->normal) - f2->plane->dist; if (dist >= -ON_EPSILON*4) // only estimate { valid++; } } if (valid >= 2) { // this splitplane forms an edge Winding *fw; Winding *bw; f->w->Clip (f2->plane->normal, f2->plane->dist, &fw, &bw); if (fw) { bface_t *front = NewFaceFromFace (f); front->w = fw; fw->getBounds (front->bounds); front->next = outside; outside = front; } if (bw) { delete f->w; f->w = bw; bw->getBounds (f->bounds); } else { FreeFace (f); f = NULL; break; } } } } else { f->next = outside; outside = f; f = NULL; } delete w; #else for (f2 = bh2->faces; f2 && f; f2 = f2->next) { f = ClipFace(f, &outside, f2->planenum, overwrite); } #endif area = f ? f->w->getArea() : 0; if (f && area < g_tiny_threshold) { Verbose("Entity %i, Brush %i: tiny penetration\n", #ifdef HLCSG_COUNT_NEW b1->originalentitynum, b1->originalbrushnum #else b1->entitynum, b1->brushnum #endif ); c_tiny_clip++; FreeFace(f); f = NULL; } if (f) { // there is one convex fragment of the original // face left inside brush2 #ifndef HLCSG_NOFAKESPLITS FreeFace(fcopy); #endif #ifdef ZHLT_DETAILBRUSH if ( #ifdef ZHLT_CLIPNODEDETAILLEVEL (hull? (b2->clipnodedetaillevel > b1->clipnodedetaillevel): (b2->detaillevel > b1->detaillevel)) #else b2->detaillevel > b1->detaillevel #endif ) { // don't chop or set contents, only nullify f->next = outside; outside = f; f->texinfo = -1; continue; } if ( #ifdef ZHLT_CLIPNODEDETAILLEVEL (hull? b2->clipnodedetaillevel < b1->clipnodedetaillevel: b2->detaillevel < b1->detaillevel) #else b2->detaillevel < b1->detaillevel #endif && b2->contents == CONTENTS_SOLID) { // real solid FreeFace (f); continue; } #endif #ifdef HLCSG_EMPTYBRUSH if (b1->contents == CONTENTS_TOEMPTY) { bool onfront = true, onback = true; for (f2 = bh2->faces; f2; f2 = f2->next) { if (f->planenum == (f2->planenum ^ 1)) onback = false; if (f->planenum == f2->planenum) onfront = false; } if (onfront && f->contents < b2->contents) f->contents = b2->contents; if (onback && f->backcontents < b2->contents) f->backcontents = b2->contents; if (f->contents == CONTENTS_SOLID && f->backcontents == CONTENTS_SOLID #ifdef HLCSG_HLBSP_SOLIDHINT && strncasecmp (GetTextureByNumber_CSG (f->texinfo), "SOLIDHINT", 9) #endif ) { FreeFace (f); } else { f->next = outside; outside = f; } continue; } #endif if (b1->contents > b2->contents #ifdef HLCSG_HLBSP_SOLIDHINT || b1->contents == b2->contents && !strncasecmp (GetTextureByNumber_CSG (f->texinfo), "SOLIDHINT", 9) #endif ) { // inside a water brush f->contents = b2->contents; f->next = outside; outside = f; } else // inside a solid brush { FreeFace(f); // throw it away } } #ifndef HLCSG_NOFAKESPLITS else { // the entire thing was on the outside, even // though the bounding boxes intersected, // which will never happen with axial planes // free the fragments chopped to the outside while (outside != oldoutside) { f2 = outside->next; FreeFace(outside); outside = f2; } // revert to the original face to avoid // unneeded false cuts fcopy->next = outside; outside = fcopy; } #endif } } // all of the faces left in outside are real surface faces SaveOutside(b1, hull, outside, b1->contents); } } // // ===================================================================================== // // ===================================================================================== // EmitPlanes // ===================================================================================== static void EmitPlanes() { int i; dplane_t* dp; plane_t* mp; g_numplanes = g_nummapplanes; mp = g_mapplanes; dp = g_dplanes; #ifdef HLCSG_HLBSP_DOUBLEPLANE { char name[_MAX_PATH]; safe_snprintf (name, _MAX_PATH, "%s.pln", g_Mapname); FILE *planeout = fopen (name, "wb"); if (!planeout) Error("Couldn't open %s", name); SafeWrite (planeout, g_mapplanes, g_nummapplanes * sizeof (plane_t)); fclose (planeout); } #endif for (i = 0; i < g_nummapplanes; i++, mp++, dp++) { //if (!(mp->redundant)) //{ // Log("EmitPlanes: plane %i non redundant\n", i); VectorCopy(mp->normal, dp->normal); dp->dist = mp->dist; dp->type = mp->type; // } //else // { // Log("EmitPlanes: plane %i redundant\n", i); // } } } // ===================================================================================== // SetModelNumbers // blah // ===================================================================================== static void SetModelNumbers() { int i; int models; char value[10]; models = 1; for (i = 1; i < g_numentities; i++) { if (g_entities[i].numbrushes) { safe_snprintf(value, sizeof(value), "*%i", models); models++; SetKeyValue(&g_entities[i], "model", value); } } } #ifdef HLCSG_COPYMODELKEYVALUE void ReuseModel () { int i; for (i = g_numentities - 1; i >= 1; i--) // so it won't affect the remaining entities in the loop when we move this entity backward { const char *name = ValueForKey (&g_entities[i], "zhlt_usemodel"); if (!*name) { continue; } int j; for (j = 1; j < g_numentities; j++) { if (*ValueForKey (&g_entities[j], "zhlt_usemodel")) { continue; } if (!strcmp (name, ValueForKey (&g_entities[j], "targetname"))) { break; } } if (j == g_numentities) { if (!strcasecmp (name, "null")) { SetKeyValue (&g_entities[i], "model", ""); continue; } Error ("zhlt_usemodel: can not find target entity '%s', or that entity is also using 'zhlt_usemodel'.\n", name); } SetKeyValue (&g_entities[i], "model", ValueForKey (&g_entities[j], "model")); if (j > i) { // move this entity backward // to prevent precache error in case of .mdl/.spr and wrong result of EntityForModel in case of map model entity_t tmp; tmp = g_entities[i]; memmove (&g_entities[i], &g_entities[i + 1], ((j + 1) - (i + 1)) * sizeof (entity_t)); g_entities[j] = tmp; } } } #endif // ===================================================================================== // SetLightStyles // ===================================================================================== #define MAX_SWITCHED_LIGHTS 32 #define MAX_LIGHTTARGETS_NAME 64 static void SetLightStyles() { int stylenum; const char* t; entity_t* e; int i, j; char value[10]; char lighttargets[MAX_SWITCHED_LIGHTS][MAX_LIGHTTARGETS_NAME]; #ifdef ZHLT_TEXLIGHT bool newtexlight = false; #endif // any light that is controlled (has a targetname) // must have a unique style number generated for it stylenum = 0; for (i = 1; i < g_numentities; i++) { e = &g_entities[i]; t = ValueForKey(e, "classname"); if (strncasecmp(t, "light", 5)) { #ifdef ZHLT_TEXLIGHT //LRC: // if it's not a normal light entity, allocate it a new style if necessary. t = ValueForKey(e, "style"); switch (atoi(t)) { case 0: // not a light, no style, generally pretty boring continue; case -1: // normal switchable texlight safe_snprintf(value, sizeof(value), "%i", 32 + stylenum); SetKeyValue(e, "style", value); stylenum++; continue; case -2: // backwards switchable texlight safe_snprintf(value, sizeof(value), "%i", -(32 + stylenum)); SetKeyValue(e, "style", value); stylenum++; continue; case -3: // (HACK) a piggyback texlight: switched on and off by triggering a real light that has the same name SetKeyValue(e, "style", "0"); // just in case the level designer didn't give it a name newtexlight = true; // don't 'continue', fall out } //LRC (ends) #else continue; #endif } t = ValueForKey(e, "targetname"); #ifdef HLCSG_STYLEHACK if (*ValueForKey (e, "zhlt_usestyle")) { t = ValueForKey(e, "zhlt_usestyle"); if (!strcasecmp (t, "null")) { t = ""; } } #endif if (!t[0]) { continue; } // find this targetname for (j = 0; j < stylenum; j++) { if (!strcmp(lighttargets[j], t)) { break; } } if (j == stylenum) { hlassume(stylenum < MAX_SWITCHED_LIGHTS, assume_MAX_SWITCHED_LIGHTS); safe_strncpy(lighttargets[j], t, MAX_LIGHTTARGETS_NAME); stylenum++; } safe_snprintf(value, sizeof(value), "%i", 32 + j); SetKeyValue(e, "style", value); } } // ===================================================================================== // ConvertHintToEmtpy // ===================================================================================== static void ConvertHintToEmpty() { int i; // Convert HINT brushes to EMPTY after they have been carved by csg for (i = 0; i < MAX_MAP_BRUSHES; i++) { if (g_mapbrushes[i].contents == CONTENTS_HINT) { g_mapbrushes[i].contents = CONTENTS_EMPTY; } } } // ===================================================================================== // WriteBSP // ===================================================================================== #ifdef HLCSG_ONLYENTS_NOWADCHANGE void LoadWadValue () { char *wadvalue; ParseFromMemory (g_dentdata, g_entdatasize); epair_t *e; entity_t ent0; entity_t *mapent = &ent0; memset (mapent, 0, sizeof (entity_t)); if (!GetToken (true)) { wadvalue = strdup (""); } else { if (strcmp (g_token, "{")) { Error ("ParseEntity: { not found"); } while (1) { if (!GetToken (true)) { Error ("ParseEntity: EOF without closing brace"); } if (!strcmp (g_token, "}")) { break; } e = ParseEpair (); e->next = mapent->epairs; mapent->epairs = e; } wadvalue = strdup (ValueForKey (mapent, "wad")); epair_t *next; for (e = mapent->epairs; e; e = next) { next = e->next; free (e->key); free (e->value); free (e); } } if (*wadvalue) { Log ("Wad files required to run the map: \"%s\"\n", wadvalue); } else { Log ("Wad files required to run the map: (None)\n"); } SetKeyValue (&g_entities[0], "wad", wadvalue); free (wadvalue); } #endif void WriteBSP(const char* const name) { char path[_MAX_PATH]; #ifdef ZHLT_DEFAULTEXTENSION_FIX safe_snprintf(path, _MAX_PATH, "%s.bsp", name); #else safe_strncpy(path, name, _MAX_PATH); DefaultExtension(path, ".bsp"); #endif SetModelNumbers(); #ifdef HLCSG_COPYMODELKEYVALUE ReuseModel(); #endif SetLightStyles(); if (!g_onlyents) WriteMiptex(); #ifdef HLCSG_ONLYENTS_NOWADCHANGE if (g_onlyents) { LoadWadValue (); } #endif UnparseEntities(); ConvertHintToEmpty(); // this is ridiculous. --vluzacn #ifdef HLCSG_CHART_FIX if (g_chart) PrintBSPFileSizes(); #endif WriteBSPFile(path); } // // ===================================================================================== // // AJM: added in function // ===================================================================================== // CopyGenerictoCLIP // clips a generic brush // ===================================================================================== /*static void CopyGenerictoCLIP(const brush_t* const b) { // code blatently ripped from CopySKYtoCLIP() int i; entity_t* mapent; brush_t* newbrush; mapent = &g_entities[b->entitynum]; mapent->numbrushes++; newbrush = &g_mapbrushes[g_nummapbrushes]; #ifdef HLCSG_COUNT_NEW newbrush->originalentitynum = b->originalentitynum; newbrush->originalbrushnum = b->originalbrushnum; #endif newbrush->entitynum = b->entitynum; newbrush->brushnum = g_nummapbrushes - mapent->firstbrush; newbrush->firstside = g_numbrushsides; newbrush->numsides = b->numsides; newbrush->contents = CONTENTS_CLIP; newbrush->noclip = 0; for (i = 0; i < b->numsides; i++) { int j; side_t* side = &g_brushsides[g_numbrushsides]; *side = g_brushsides[b->firstside + i]; safe_strncpy(side->td.name, "CLIP", sizeof(side->td.name)); for (j = 0; j < NUM_HULLS; j++) { newbrush->hulls[j].faces = NULL; newbrush->hulls[j].bounds = b->hulls[j].bounds; } g_numbrushsides++; hlassume(g_numbrushsides < MAX_MAP_SIDES, assume_MAX_MAP_SIDES); } g_nummapbrushes++; hlassume(g_nummapbrushes < MAX_MAP_BRUSHES, assume_MAX_MAP_BRUSHES); }*/ #ifdef HLCSG_CLIPECONOMY // AJM: added in unsigned int BrushClipHullsDiscarded = 0; unsigned int ClipNodesDiscarded = 0; //AJM: added in function static void MarkEntForNoclip(entity_t* ent) { int i; brush_t* b; for (i = ent->firstbrush; i < ent->firstbrush + ent->numbrushes; i++) { b = &g_mapbrushes[i]; b->noclip = 1; BrushClipHullsDiscarded++; ClipNodesDiscarded += b->numsides; } } // AJM // ===================================================================================== // CheckForNoClip // marks the noclip flag on any brushes that dont need clipnode generation, eg. func_illusionaries // ===================================================================================== static void CheckForNoClip() { int i; entity_t* ent; char entclassname[MAX_KEY]; int spawnflags; #ifdef HLCSG_CUSTOMHULL int count = 0; #endif if (!g_bClipNazi) return; // NO CLIP FOR YOU!!! for (i = 0; i < g_numentities; i++) { if (!g_entities[i].numbrushes) continue; // not a model if (!i) continue; // dont waste our time with worldspawn ent = &g_entities[i]; strcpy_s(entclassname, ValueForKey(ent, "classname")); spawnflags = atoi(ValueForKey(ent, "spawnflags")); int skin = IntForKey(ent, "skin"); //vluzacn #ifndef HLCSG_CUSTOMHULL // condition 0, it's marked noclip (KGP) if(strlen(ValueForKey(ent,"zhlt_noclip")) && strcmp(ValueForKey(ent,"zhlt_noclip"),"0")) { MarkEntForNoclip(ent); } // condition 1 //modified. --vluzacn else #endif if ((skin != -16) && ( !strcmp(entclassname, "env_bubbles") || !strcmp(entclassname, "func_illusionary") || (spawnflags & 8) && ( /* NOTE: func_doors as far as i can tell may need clipnodes for their player collision detection, so for now, they stay out of it. */ !strcmp(entclassname, "func_train") || !strcmp(entclassname, "func_door") || !strcmp(entclassname, "func_water") || !strcmp(entclassname, "func_door_rotating") || !strcmp(entclassname, "func_pendulum") || !strcmp(entclassname, "func_train") || !strcmp(entclassname, "func_tracktrain") || !strcmp(entclassname, "func_vehicle") ) || (skin != 0) && (!strcmp(entclassname, "func_door") || !strcmp(entclassname, "func_water")) || (spawnflags & 2) && (!strcmp(entclassname, "func_conveyor")) || (spawnflags & 1) && (!strcmp(entclassname, "func_rot_button")) || (spawnflags & 64) && (!strcmp(entclassname, "func_rotating")) )) { MarkEntForNoclip(ent); #ifdef HLCSG_CUSTOMHULL count++; #endif } /* // condition 6: its a func_wall, while we noclip it, we remake the clipnodes manually else if (!strncasecmp(entclassname, "func_wall", 9)) { for (int j = ent->firstbrush; j < ent->firstbrush + ent->numbrushes; j++) CopyGenerictoCLIP(&g_mapbrushes[i]); MarkEntForNoclip(ent); } */ } #ifdef HLCSG_CUSTOMHULL Log("%i entities discarded from clipping hulls\n", count); #else Log("%i brushes (totalling %i sides) discarded from clipping hulls\n", BrushClipHullsDiscarded, ClipNodesDiscarded); #endif } #endif // ===================================================================================== // ProcessModels // ===================================================================================== #ifndef HLCSG_SORTBRUSH_FIX #define NUM_TYPECONTENTS 5 // AJM: should reflect the number of values below int typecontents[NUM_TYPECONTENTS] = { CONTENTS_WATER, CONTENTS_SLIME, CONTENTS_LAVA, CONTENTS_SKY, CONTENTS_HINT }; #endif static void ProcessModels() { int i, j, type; int placed; int first, contents; brush_t temp; for (i = 0; i < g_numentities; i++) { if (!g_entities[i].numbrushes) // only models continue; // sort the contents down so stone bites water, etc first = g_entities[i].firstbrush; #ifdef HLCSG_SORTBRUSH_KEEPORDER brush_t *temps = (brush_t *)malloc (g_entities[i].numbrushes * sizeof (brush_t)); hlassume (temps, assume_NoMemory); for (j = 0; j < g_entities[i].numbrushes; j++) { temps[j] = g_mapbrushes[first + j]; } int placedcontents; bool b_placedcontents = false; for (placed = 0; placed < g_entities[i].numbrushes; ) { bool b_contents = false; for (j = 0; j < g_entities[i].numbrushes; j++) { brush_t *brush = &temps[j]; if (b_placedcontents && brush->contents <= placedcontents) continue; if (b_contents && brush->contents >= contents) continue; b_contents = true; contents = brush->contents; } for (j = 0; j < g_entities[i].numbrushes; j++) { brush_t *brush = &temps[j]; if (brush->contents == contents) { g_mapbrushes[first + placed] = *brush; placed++; } } b_placedcontents = true; placedcontents = contents; } free (temps); #else #ifdef HLCSG_SORTBRUSH_FIX placed = 0; while (placed < g_entities[i].numbrushes) { for (j = placed; j < g_entities[i].numbrushes; j++) { if (j == placed) { contents = g_mapbrushes[first + j].contents; } else { contents = qmin(g_mapbrushes[first + j].contents, contents); } } for (j = placed; j < g_entities[i].numbrushes; j++) { if (g_mapbrushes[first + j].contents == contents) { temp = g_mapbrushes[first + placed]; g_mapbrushes[first + placed] = g_mapbrushes[first + j]; g_mapbrushes[first + j] = temp; placed++; } } } #else placed = 0; for (type = 0; type < NUM_TYPECONTENTS; type++) // for each of the contents types { contents = typecontents[type]; for (j = placed + 1; j < g_entities[i].numbrushes; j++) // for each of the model's brushes { // if this brush is of the contents type in this for iteration if (g_mapbrushes[first + j].contents == contents) { temp = g_mapbrushes[first + placed]; g_mapbrushes[first + placed] = g_mapbrushes[j]; g_mapbrushes[j] = temp; placed++; } } } #endif #endif // csg them in order if (i == 0) // if its worldspawn.... { NamedRunThreadsOnIndividual(g_entities[i].numbrushes, g_estimate, CSGBrush); CheckFatal(); } else { for (j = 0; j < g_entities[i].numbrushes; j++) { CSGBrush(first + j); } } // write end of model marker for (j = 0; j < NUM_HULLS; j++) { #ifdef ZHLT_DETAILBRUSH fprintf (out[j], "-1 -1 -1 -1 -1\n"); fprintf (out_detailbrush[j], "-1\n"); #else fprintf(out[j], "-1 -1 -1 -1\n"); #endif } } } // ===================================================================================== // SetModelCenters // ===================================================================================== static void SetModelCenters(int entitynum) { int i; int last; char string[MAXTOKEN]; entity_t* e = &g_entities[entitynum]; BoundingBox bounds; vec3_t center; if ((entitynum == 0) || (e->numbrushes == 0)) // skip worldspawn and point entities return; if (!*ValueForKey(e, "light_origin")) // skip if its not a zhlt_flags light_origin return; for (i = e->firstbrush, last = e->firstbrush + e->numbrushes; i < last; i++) { if (g_mapbrushes[i].contents != CONTENTS_ORIGIN #ifdef HLCSG_HLBSP_CUSTOMBOUNDINGBOX && g_mapbrushes[i].contents != CONTENTS_BOUNDINGBOX #endif ) { bounds.add(g_mapbrushes[i].hulls->bounds); } } VectorAdd(bounds.m_Mins, bounds.m_Maxs, center); VectorScale(center, 0.5, center); safe_snprintf(string, MAXTOKEN, "%i %i %i", (int)center[0], (int)center[1], (int)center[2]); SetKeyValue(e, "model_center", string); } // // ===================================================================================== // // ===================================================================================== // BoundWorld // ===================================================================================== static void BoundWorld() { int i; brushhull_t* h; world_bounds.reset(); for (i = 0; i < g_nummapbrushes; i++) { h = &g_mapbrushes[i].hulls[0]; if (!h->faces) { continue; } world_bounds.add(h->bounds); } Verbose("World bounds: (%i %i %i) to (%i %i %i)\n", (int)world_bounds.m_Mins[0], (int)world_bounds.m_Mins[1], (int)world_bounds.m_Mins[2], (int)world_bounds.m_Maxs[0], (int)world_bounds.m_Maxs[1], (int)world_bounds.m_Maxs[2]); } // ===================================================================================== // Usage // prints out usage sheet // ===================================================================================== static void Usage() { Banner(); // TODO: Call banner from main CSG process? Log("\n-= %s Options =-\n\n", g_Program); #ifdef ZHLT_CONSOLE Log(" -console # : Set to 0 to turn off the pop-up console (default is 1)\n"); #endif #ifdef ZHLT_LANGFILE Log(" -lang file : localization file\n"); #endif Log(" -nowadtextures : include all used textures into bsp\n"); Log(" -wadinclude file : place textures used from wad specified into bsp\n"); Log(" -noclip : don't create clipping hull\n"); #ifdef HLCSG_CLIPECONOMY // AJM #ifdef HLCSG_CUSTOMHULL // default clip economy off Log(" -clipeconomy : turn clipnode economy mode on\n"); #else Log(" -noclipeconomy : turn clipnode economy mode off\n"); #endif #endif #ifdef HLCSG_PRECISIONCLIP // KGP Log(" -cliptype value : set to smallest, normalized, simple, precise, or legacy (default)\n"); #endif #ifdef HLCSG_NULLIFY_INVISIBLE // KGP Log(" -nullfile file : specify list of entities to retexture with NULL\n"); #endif Log(" -onlyents : do an entity update from .map to .bsp\n"); Log(" -noskyclip : disable automatic clipping of SKY brushes\n"); Log(" -tiny # : minmum brush face surface area before it is discarded\n"); Log(" -brushunion # : threshold to warn about overlapping brushes\n\n"); Log(" -hullfile file : Reads in custom collision hull dimensions\n"); #ifdef HLCSG_WADCFG_NEW Log(" -wadcfgfile file : wad configuration file\n"); Log(" -wadconfig name : use the old wad configuration approach (select a group from wad.cfg)\n"); #endif Log(" -texdata # : Alter maximum texture memory limit (in kb)\n"); Log(" -lightdata # : Alter maximum lighting memory limit (in kb)\n"); Log(" -chart : display bsp statitics\n"); Log(" -low | -high : run program an altered priority level\n"); Log(" -nolog : don't generate the compile logfiles\n"); #ifdef HLCSG_KEEPLOG Log(" -noresetlog : Do not delete log file\n"); #endif Log(" -threads # : manually specify the number of threads to run\n"); #ifdef SYSTEM_WIN32 Log(" -estimate : display estimated time during compile\n"); #endif #ifdef ZHLT_PROGRESSFILE // AJM Log(" -progressfile path : specify the path to a file for progress estimate output\n"); #endif #ifdef SYSTEM_POSIX Log(" -noestimate : do not display continuous compile time estimates\n"); #endif Log(" -verbose : compile with verbose messages\n"); Log(" -noinfo : Do not show tool configuration information\n"); #ifdef ZHLT_NULLTEX // AJM Log(" -nonulltex : Turns off null texture stripping\n"); #endif #ifdef HLCSG_NULLIFYAAATRIGGER Log(" -nonullifytrigger: don't remove 'aaatrigger' texture\n"); #endif #ifdef ZHLT_DETAIL // AJM Log(" -nodetail : dont handle detail brushes\n"); #endif #ifdef HLCSG_OPTIMIZELIGHTENTITY Log(" -nolightopt : don't optimize engine light entities\n"); #endif #ifdef HLCSG_GAMETEXTMESSAGE_UTF8 Log(" -notextconvert : don't convert game_text message from Windows ANSI to UTF8 format\n"); #endif Log(" -dev # : compile with developer message\n\n"); #ifndef HLCSG_WADCFG_NEW #ifdef HLCSG_WADCFG // AJM Log(" -wadconfig name : Specify a configuration to use from wad.cfg\n"); Log(" -wadcfgfile path : Manually specify a path to the wad.cfg file\n"); //JK: #endif #endif #ifdef HLCSG_AUTOWAD // AJM: Log(" -wadautodetect : Force auto-detection of wadfiles\n"); #endif #ifdef HLCSG_SCALESIZE Log(" -scale # : Scale the world. Use at your own risk.\n"); #endif Log(" mapfile : The mapfile to compile\n\n"); exit(1); } // ===================================================================================== // DumpWadinclude // prints out the wadinclude list // ===================================================================================== static void DumpWadinclude() { Log("Wadinclude list :\n"); WadInclude_i it; for (it = g_WadInclude.begin(); it != g_WadInclude.end(); it++) { Log("[%s]\n", it->c_str()); } } // ===================================================================================== // Settings // prints out settings sheet // ===================================================================================== static void Settings() { char* tmp; if (!g_info) return; Log("\nCurrent %s Settings\n", g_Program); Log("Name | Setting | Default\n" "---------------------|-----------|-------------------------\n"); // ZHLT Common Settings if (DEFAULT_NUMTHREADS == -1) { Log("threads [ %7d ] [ Varies ]\n", g_numthreads); } else { Log("threads [ %7d ] [ %7d ]\n", g_numthreads, DEFAULT_NUMTHREADS); } Log("verbose [ %7s ] [ %7s ]\n", g_verbose ? "on" : "off", DEFAULT_VERBOSE ? "on" : "off"); Log("log [ %7s ] [ %7s ]\n", g_log ? "on" : "off", DEFAULT_LOG ? "on" : "off"); #ifdef HLCSG_KEEPLOG Log("reset logfile [ %7s ] [ %7s ]\n", g_resetlog ? "on" : "off", DEFAULT_RESETLOG ? "on" : "off"); #endif Log("developer [ %7d ] [ %7d ]\n", g_developer, DEFAULT_DEVELOPER); Log("chart [ %7s ] [ %7s ]\n", g_chart ? "on" : "off", DEFAULT_CHART ? "on" : "off"); Log("estimate [ %7s ] [ %7s ]\n", g_estimate ? "on" : "off", DEFAULT_ESTIMATE ? "on" : "off"); Log("max texture memory [ %7d ] [ %7d ]\n", g_max_map_miptex, DEFAULT_MAX_MAP_MIPTEX); Log("max lighting memory [ %7d ] [ %7d ]\n", g_max_map_lightdata, DEFAULT_MAX_MAP_LIGHTDATA); switch (g_threadpriority) { case eThreadPriorityNormal: default: tmp = "Normal"; break; case eThreadPriorityLow: tmp = "Low"; break; case eThreadPriorityHigh: tmp = "High"; break; } Log("priority [ %7s ] [ %7s ]\n", tmp, "Normal"); Log("\n"); // HLCSG Specific Settings Log("noclip [ %7s ] [ %7s ]\n", g_noclip ? "on" : "off", DEFAULT_NOCLIP ? "on" : "off"); #ifdef ZHLT_NULLTEX // AJM: Log("null texture stripping[ %7s ] [ %7s ]\n", g_bUseNullTex ? "on" : "off", DEFAULT_NULLTEX ? "on" : "off"); #endif #ifdef ZHLT_DETAIL // AJM Log("detail brushes [ %7s ] [ %7s ]\n", g_bDetailBrushes ? "on" : "off", DEFAULT_DETAIL ? "on" : "off"); #endif #ifdef HLCSG_CLIPECONOMY // AJM Log("clipnode economy mode [ %7s ] [ %7s ]\n", g_bClipNazi ? "on" : "off", DEFAULT_CLIPNAZI ? "on" : "off"); #endif #ifdef HLCSG_PRECISIONCLIP // KGP Log("clip hull type [ %7s ] [ %7s ]\n", GetClipTypeString(g_cliptype), GetClipTypeString(DEFAULT_CLIPTYPE)); #endif Log("onlyents [ %7s ] [ %7s ]\n", g_onlyents ? "on" : "off", DEFAULT_ONLYENTS ? "on" : "off"); Log("wadtextures [ %7s ] [ %7s ]\n", g_wadtextures ? "on" : "off", DEFAULT_WADTEXTURES ? "on" : "off"); Log("skyclip [ %7s ] [ %7s ]\n", g_skyclip ? "on" : "off", DEFAULT_SKYCLIP ? "on" : "off"); Log("hullfile [ %7s ] [ %7s ]\n", g_hullfile ? g_hullfile : "None", "None"); #ifdef HLCSG_WADCFG_NEW Log("wad configuration file[ %7s ] [ %7s ]\n", g_wadcfgfile? g_wadcfgfile: "None", "None"); Log("wad.cfg group name [ %7s ] [ %7s ]\n", g_wadconfigname? g_wadconfigname: "None", "None"); #endif #ifdef HLCSG_NULLIFY_INVISIBLE // KGP Log("nullfile [ %7s ] [ %7s ]\n", g_nullfile ? g_nullfile : "None", "None"); #endif #ifdef HLCSG_NULLIFYAAATRIGGER Log("nullify trigger [ %7s ] [ %7s ]\n", g_nullifytrigger? "on": "off", DEFAULT_NULLIFYTRIGGER? "on": "off"); #endif // calc min surface area { char tiny_penetration[10]; char default_tiny_penetration[10]; safe_snprintf(tiny_penetration, sizeof(tiny_penetration), "%3.3f", g_tiny_threshold); safe_snprintf(default_tiny_penetration, sizeof(default_tiny_penetration), "%3.3f", DEFAULT_TINY_THRESHOLD); Log("min surface area [ %7s ] [ %7s ]\n", tiny_penetration, default_tiny_penetration); } // calc union threshold { char brush_union[10]; char default_brush_union[10]; safe_snprintf(brush_union, sizeof(brush_union), "%3.3f", g_BrushUnionThreshold); safe_snprintf(default_brush_union, sizeof(default_brush_union), "%3.3f", DEFAULT_BRUSH_UNION_THRESHOLD); Log("brush union threshold [ %7s ] [ %7s ]\n", brush_union, default_brush_union); } #ifdef HLCSG_SCALESIZE { char buf1[10]; char buf2[10]; if (g_scalesize > 0) safe_snprintf(buf1, sizeof(buf1), "%3.3f", g_scalesize); else strcpy (buf1, "None"); if (DEFAULT_SCALESIZE > 0) safe_snprintf(buf2, sizeof(buf2), "%3.3f", DEFAULT_SCALESIZE); else strcpy (buf2, "None"); Log("map scaling [ %7s ] [ %7s ]\n", buf1, buf2); } #endif #ifdef HLCSG_OPTIMIZELIGHTENTITY Log("light name optimize [ %7s ] [ %7s ]\n", !g_nolightopt? "on" : "off", !DEFAULT_NOLIGHTOPT? "on" : "off"); #endif #ifdef HLCSG_GAMETEXTMESSAGE_UTF8 Log("convert game_text [ %7s ] [ %7s ]\n", !g_noutf8? "on" : "off", !DEFAULT_NOUTF8? "on" : "off"); #endif Log("\n"); } // AJM: added in // ===================================================================================== // CSGCleanup // ===================================================================================== void CSGCleanup() { //Log("CSGCleanup\n"); #ifndef HLCSG_AUTOWAD_NEW #ifdef HLCSG_AUTOWAD autowad_cleanup(); #endif #endif #ifndef HLCSG_WADCFG_NEW #ifdef HLCSG_WADCFG WadCfg_cleanup(); #endif #endif FreeWadPaths(); } // ===================================================================================== // Main // Oh, come on. // ===================================================================================== int main(const int argc, char** argv) { int i; char name[_MAX_PATH]; // mapanme double start, end; // start/end time log const char* mapname_from_arg = NULL; // mapname path from passed argvar g_Program = "hlcsg"; #ifdef ZHLT_PARAMFILE int argcold = argc; char ** argvold = argv; { int argc; char ** argv; ParseParamFile (argcold, argvold, argc, argv); { #endif #ifdef ZHLT_CONSOLE if (InitConsole (argc, argv) < 0) Usage(); #endif if (argc == 1) Usage(); // Hard coded list of -wadinclude files, used for HINT texture brushes so lazy // mapmakers wont cause beta testers (or possibly end users) to get a wad // error on zhlt.wad etc g_WadInclude.push_back("zhlt.wad"); #ifndef HLCSG_WADCFG_NEW #ifdef HLCSG_WADCFG memset(wadconfigname, 0, sizeof(wadconfigname));//AJM #endif #endif #ifdef HLCSG_HULLBRUSH InitDefaultHulls (); #endif // detect argv for (i = 1; i < argc; i++) { if (!strcasecmp(argv[i], "-threads")) { if (i + 1 < argc) //added "1" .--vluzacn { g_numthreads = atoi(argv[++i]); if (g_numthreads < 1) { Log("Expected value of at least 1 for '-threads'\n"); Usage(); } } else { Usage(); } } #ifdef ZHLT_CONSOLE else if (!strcasecmp(argv[i], "-console")) { #ifndef SYSTEM_WIN32 Warning("The option '-console #' is only valid for Windows."); #endif if (i + 1 < argc) ++i; else Usage(); } #endif #ifdef SYSTEM_WIN32 else if (!strcasecmp(argv[i], "-estimate")) { g_estimate = true; } #endif #ifdef SYSTEM_POSIX else if (!strcasecmp(argv[i], "-noestimate")) { g_estimate = false; } #endif else if (!strcasecmp(argv[i], "-dev")) { if (i + 1 < argc) //added "1" .--vluzacn { g_developer = (developer_level_t)atoi(argv[++i]); } else { Usage(); } } else if (!strcasecmp(argv[i], "-verbose")) { g_verbose = true; } else if (!strcasecmp(argv[i], "-noinfo")) { g_info = false; } else if (!strcasecmp(argv[i], "-chart")) { g_chart = true; } else if (!strcasecmp(argv[i], "-low")) { g_threadpriority = eThreadPriorityLow; } else if (!strcasecmp(argv[i], "-high")) { g_threadpriority = eThreadPriorityHigh; } else if (!strcasecmp(argv[i], "-nolog")) { g_log = false; } else if (!strcasecmp(argv[i], "-skyclip")) { g_skyclip = true; } else if (!strcasecmp(argv[i], "-noskyclip")) { g_skyclip = false; } else if (!strcasecmp(argv[i], "-noclip")) { g_noclip = true; } else if (!strcasecmp(argv[i], "-onlyents")) { g_onlyents = true; } #ifdef ZHLT_NULLTEX // AJM: added in -nonulltex else if (!strcasecmp(argv[i], "-nonulltex")) { g_bUseNullTex = false; } #endif #ifdef HLCSG_CLIPECONOMY // AJM: added in -noclipeconomy #ifdef HLCSG_CUSTOMHULL // default clip economy off else if (!strcasecmp(argv[i], "-clipeconomy")) { g_bClipNazi = true; } #else else if (!strcasecmp(argv[i], "-noclipeconomy")) { g_bClipNazi = false; } #endif #endif #ifdef HLCSG_PRECISIONCLIP // KGP: added in -cliptype else if (!strcasecmp(argv[i], "-cliptype")) { if (i + 1 < argc) //added "1" .--vluzacn { ++i; if(!strcasecmp(argv[i],"smallest")) { g_cliptype = clip_smallest; } else if(!strcasecmp(argv[i],"normalized")) { g_cliptype = clip_normalized; } else if(!strcasecmp(argv[i],"simple")) { g_cliptype = clip_simple; } else if(!strcasecmp(argv[i],"precise")) { g_cliptype = clip_precise; } else if(!strcasecmp(argv[i],"legacy")) { g_cliptype = clip_legacy; } } else { Log("Error: -cliptype: incorrect usage of parameter\n"); Usage(); } } #endif #ifndef HLCSG_WADCFG_NEW #ifdef HLCSG_WADCFG // AJM: added in -wadconfig else if (!strcasecmp(argv[i], "-wadconfig")) { if (i + 1 < argc) //added "1" .--vluzacn { safe_strncpy(wadconfigname, argv[++i], MAX_WAD_CFG_NAME); if (strlen(argv[i]) > MAX_WAD_CFG_NAME) { Warning("wad configuration name was truncated to %i chars", MAX_WAD_CFG_NAME); wadconfigname[MAX_WAD_CFG_NAME] = 0; } } else { Log("Error: -wadconfig: incorrect usage of parameter\n"); Usage(); } } //JK: added in -wadcfgfile else if (!strcasecmp(argv[i], "-wadcfgfile")) { if (i + 1 < argc) //added "1" .--vluzacn { g_wadcfgfile = argv[++i]; } else { Log("Error: -wadcfgfile: incorrect usage of parameter\n"); Usage(); } } #endif #endif #ifdef HLCSG_NULLIFY_INVISIBLE else if (!strcasecmp(argv[i], "-nullfile")) { if (i + 1 < argc) //added "1" .--vluzacn { g_nullfile = argv[++i]; } else { Log("Error: -nullfile: expected path to null ent file following parameter\n"); Usage(); } } #endif #ifdef HLCSG_AUTOWAD // AJM else if (!strcasecmp(argv[i], "-wadautodetect")) { g_bWadAutoDetect = true; } #endif #ifdef ZHLT_DETAIL // AJM else if (!strcasecmp(argv[i], "-nodetail")) { g_bDetailBrushes = false; } #endif #ifdef ZHLT_PROGRESSFILE // AJM else if (!strcasecmp(argv[i], "-progressfile")) { if (i + 1 < argc) //added "1" .--vluzacn { g_progressfile = argv[++i]; } else { Log("Error: -progressfile: expected path to progress file following parameter\n"); Usage(); } } #endif else if (!strcasecmp(argv[i], "-nowadtextures")) { g_wadtextures = false; } else if (!strcasecmp(argv[i], "-wadinclude")) { if (i + 1 < argc) //added "1" .--vluzacn { g_WadInclude.push_back(argv[++i]); } else { Usage(); } } else if (!strcasecmp(argv[i], "-texdata")) { if (i + 1 < argc) //added "1" .--vluzacn { int x = atoi(argv[++i]) * 1024; //if (x > g_max_map_miptex) //--vluzacn { g_max_map_miptex = x; } } else { Usage(); } } else if (!strcasecmp(argv[i], "-lightdata")) { if (i + 1 < argc) //added "1" .--vluzacn { int x = atoi(argv[++i]) * 1024; //if (x > g_max_map_lightdata) //--vluzacn { g_max_map_lightdata = x; } } else { Usage(); } } else if (!strcasecmp(argv[i], "-brushunion")) { if (i + 1 < argc) //added "1" .--vluzacn { g_BrushUnionThreshold = (float)atof(argv[++i]); } else { Usage(); } } else if (!strcasecmp(argv[i], "-tiny")) { if (i + 1 < argc) //added "1" .--vluzacn { g_tiny_threshold = (float)atof(argv[++i]); } else { Usage(); } } else if (!strcasecmp(argv[i], "-hullfile")) { if (i + 1 < argc) //added "1" .--vluzacn { g_hullfile = argv[++i]; } else { Usage(); } } #ifdef HLCSG_WADCFG_NEW else if (!strcasecmp (argv[i], "-wadcfgfile")) { if (i + 1 < argc) { g_wadcfgfile = argv[++i]; } else { Usage (); } } else if (!strcasecmp (argv[i], "-wadconfig")) { if (i + 1 < argc) { g_wadconfigname = argv[++i]; } else { Usage (); } } #endif #ifdef HLCSG_SCALESIZE else if (!strcasecmp(argv[i], "-scale")) { if (i + 1 < argc) { g_scalesize = atof(argv[++i]); } else { Usage(); } } #endif #ifdef ZHLT_LANGFILE else if (!strcasecmp (argv[i], "-lang")) { if (i + 1 < argc) { char tmp[_MAX_PATH]; #ifdef SYSTEM_WIN32 GetModuleFileName (NULL, tmp, _MAX_PATH); #else safe_strncpy (tmp, argv[0], _MAX_PATH); #endif LoadLangFile (argv[++i], tmp); } else { Usage(); } } #endif #ifdef HLCSG_KEEPLOG else if (!strcasecmp (argv[i], "-noresetlog")) { g_resetlog = false; } #endif #ifdef HLCSG_OPTIMIZELIGHTENTITY else if (!strcasecmp (argv[i], "-nolightopt")) { g_nolightopt = true; } #endif #ifdef HLCSG_GAMETEXTMESSAGE_UTF8 else if (!strcasecmp (argv[i], "-notextconvert")) { g_noutf8 = true; } #endif #ifdef HLCSG_VIEWSURFACE else if (!strcasecmp (argv[i], "-viewsurface")) { g_viewsurface = true; } #endif #ifdef HLCSG_NULLIFYAAATRIGGER else if (!strcasecmp (argv[i], "-nonullifytrigger")) { g_nullifytrigger = false; } #endif else if (argv[i][0] == '-') { Log("Unknown option \"%s\"\n", argv[i]); Usage(); } else if (!mapname_from_arg) { mapname_from_arg = argv[i]; } else { Log("Unknown option \"%s\"\n", argv[i]); Usage(); } } // no mapfile? if (!mapname_from_arg) { // what a shame. Log("No mapfile specified\n"); Usage(); } // handle mapname safe_strncpy(g_Mapname, mapname_from_arg, _MAX_PATH); FlipSlashes(g_Mapname); StripExtension(g_Mapname); // onlyents if (!g_onlyents) ResetTmpFiles(); // other stuff ResetErrorLog(); #ifdef HLCSG_KEEPLOG if (!g_onlyents && g_resetlog) #endif ResetLog(); OpenLog(g_clientid); atexit(CloseLog); #ifdef ZHLT_PARAMFILE LogStart(argcold, argvold); { int i; Log("Arguments: "); for (i = 1; i < argc; i++) { if (strchr(argv[i], ' ')) { Log("\"%s\" ", argv[i]); } else { Log("%s ", argv[i]); } } Log("\n"); } #else LogStart(argc, argv); #endif #ifdef ZHLT_64BIT_FIX #ifdef PLATFORM_CAN_CALC_EXTENT hlassume (CalcFaceExtents_test (), assume_first); #endif #endif atexit(CSGCleanup); // AJM dtexdata_init(); atexit(dtexdata_free); // START CSG // AJM: re-arranged some stuff up here so that the mapfile is loaded // before settings are finalised and printed out, so that the info_compile_parameters // entity can be dealt with effectively start = I_FloatTime(); #ifdef HLCSG_HULLFILE_AUTOPATH if (g_hullfile) { char temp[_MAX_PATH]; char test[_MAX_PATH]; safe_strncpy (temp, g_Mapname, _MAX_PATH); ExtractFilePath (temp, test); safe_strncat (test, g_hullfile, _MAX_PATH); if (q_exists (test)) { g_hullfile = strdup (test); } else { #ifdef SYSTEM_WIN32 GetModuleFileName (NULL, temp, _MAX_PATH); #else safe_strncpy (temp, argv[0], _MAX_PATH); #endif ExtractFilePath (temp, test); safe_strncat (test, g_hullfile, _MAX_PATH); if (q_exists (test)) { g_hullfile = strdup (test); } } } if (g_nullfile) { char temp[_MAX_PATH]; char test[_MAX_PATH]; safe_strncpy (temp, g_Mapname, _MAX_PATH); ExtractFilePath (temp, test); safe_strncat (test, g_nullfile, _MAX_PATH); if (q_exists (test)) { g_nullfile = strdup (test); } else { #ifdef SYSTEM_WIN32 GetModuleFileName (NULL, temp, _MAX_PATH); #else safe_strncpy (temp, argv[0], _MAX_PATH); #endif ExtractFilePath (temp, test); safe_strncat (test, g_nullfile, _MAX_PATH); if (q_exists (test)) { g_nullfile = strdup (test); } } } #endif #ifdef HLCSG_WADCFG_NEW if (g_wadcfgfile) { char temp[_MAX_PATH]; char test[_MAX_PATH]; safe_strncpy (temp, g_Mapname, _MAX_PATH); ExtractFilePath (temp, test); safe_strncat (test, g_wadcfgfile, _MAX_PATH); if (q_exists (test)) { g_wadcfgfile = strdup (test); } else { #ifdef SYSTEM_WIN32 GetModuleFileName (NULL, temp, _MAX_PATH); #else safe_strncpy (temp, argv[0], _MAX_PATH); #endif ExtractFilePath (temp, test); safe_strncat (test, g_wadcfgfile, _MAX_PATH); if (q_exists (test)) { g_wadcfgfile = strdup (test); } } } #endif LoadHullfile(g_hullfile); // if the user specified a hull file, load it now #ifdef HLCSG_NULLIFY_INVISIBLE if(g_bUseNullTex) { properties_initialize(g_nullfile); } #endif safe_strncpy(name, mapname_from_arg, _MAX_PATH); // make a copy of the nap name #ifdef ZHLT_DEFAULTEXTENSION_FIX FlipSlashes(name); #endif DefaultExtension(name, ".map"); // might be .reg LoadMapFile(name); ThreadSetDefault(); ThreadSetPriority(g_threadpriority); Settings(); #ifdef HLCSG_GAMETEXTMESSAGE_UTF8 if (!g_noutf8) { int count = 0; for (i = 0; i < g_numentities; i++) { entity_t *ent = &g_entities[i]; const char *value; char *newvalue; if (strcmp (ValueForKey (ent, "classname"), "game_text")) { continue; } value = ValueForKey (ent, "message"); if (*value) { newvalue = ANSItoUTF8 (value); if (strcmp (newvalue, value)) { SetKeyValue (ent, "message", newvalue); count++; } free (newvalue); } } if (count) { Log ("%d game_text messages converted from Windows ANSI(CP_ACP) to UTF-8 encoding\n", count); } } #endif #ifdef HLCSG_ONLYENTS_NOWADCHANGE if (!g_onlyents) { #endif #ifdef HLCSG_WADCFG_NEW if (g_wadconfigname) { char temp[_MAX_PATH]; char test[_MAX_PATH]; #ifdef SYSTEM_WIN32 GetModuleFileName (NULL, temp, _MAX_PATH); #else safe_strncpy (temp, argv[0], _MAX_PATH); #endif ExtractFilePath (temp, test); safe_strncat (test, "wad.cfg", _MAX_PATH); if (g_wadcfgfile) { safe_strncpy (test, g_wadcfgfile, _MAX_PATH); } LoadWadconfig (test, g_wadconfigname); } else if (g_wadcfgfile) { if (!q_exists (g_wadcfgfile)) { Error("Couldn't find wad configuration file '%s'\n", g_wadcfgfile); } LoadWadcfgfile (g_wadcfgfile); } else { Log("Using mapfile wad configuration\n"); GetUsedWads(); } #endif #ifndef HLCSG_WADCFG_NEW #ifdef HLCSG_WADCFG // AJM // figure out what to do with the texture settings if (wadconfigname[0]) // custom wad configuations will take precedence { LoadWadConfigFile(); ProcessWadConfiguration(); } else { Log("Using mapfile wad configuration\n"); } if (!g_bWadConfigsLoaded) // dont try and override wad.cfg #endif { GetUsedWads(); } #endif #ifdef HLCSG_AUTOWAD if (g_bWadAutoDetect) { Log("Wadfiles not in use by the map will be excluded\n"); } #endif DumpWadinclude(); Log("\n"); #ifdef HLCSG_ONLYENTS_NOWADCHANGE } #endif // if onlyents, just grab the entites and resave if (g_onlyents) { char out[_MAX_PATH]; safe_snprintf(out, _MAX_PATH, "%s.bsp", g_Mapname); LoadBSPFile(out); #ifndef HLCSG_ONLYENTS_NOWADCHANGE LoadWadincludeFile(g_Mapname); HandleWadinclude(); #endif // Write it all back out again. #ifndef HLCSG_CHART_FIX if (g_chart) { PrintBSPFileSizes(); } #endif WriteBSP(g_Mapname); end = I_FloatTime(); LogTimeElapsed(end - start); return 0; } #ifndef HLCSG_ONLYENTS_NOWADCHANGE else { SaveWadincludeFile(g_Mapname); } #endif #ifdef HLCSG_CLIPECONOMY // AJM CheckForNoClip(); #endif // createbrush NamedRunThreadsOnIndividual(g_nummapbrushes, g_estimate, CreateBrush); CheckFatal(); #ifdef HLCSG_PRECISIONCLIP // KGP - drop TEX_BEVEL flag #ifndef HLCSG_CUSTOMHULL FixBevelTextures(); #endif #endif // boundworld BoundWorld(); Verbose("%5i map planes\n", g_nummapplanes); // Set model centers for (i = 0; i < g_numentities; i++) SetModelCenters (i); //NamedRunThreadsOnIndividual(g_numentities, g_estimate, SetModelCenters); //--vluzacn // Calc brush unions if ((g_BrushUnionThreshold > 0.0) && (g_BrushUnionThreshold <= 100.0)) { NamedRunThreadsOnIndividual(g_nummapbrushes, g_estimate, CalculateBrushUnions); } // open hull files for (i = 0; i < NUM_HULLS; i++) { char name[_MAX_PATH]; safe_snprintf(name, _MAX_PATH, "%s.p%i", g_Mapname, i); out[i] = fopen(name, "w"); if (!out[i]) Error("Couldn't open %s", name); #ifdef ZHLT_DETAILBRUSH safe_snprintf(name, _MAX_PATH, "%s.b%i", g_Mapname, i); out_detailbrush[i] = fopen(name, "w"); if (!out_detailbrush[i]) Error("Couldn't open %s", name); #endif #ifdef HLCSG_VIEWSURFACE if (g_viewsurface) { safe_snprintf (name, _MAX_PATH, "%s_surface%i.pts", g_Mapname, i); out_view[i] = fopen (name, "w"); if (!out[i]) Error ("Counldn't open %s", name); } #endif } #ifdef HLCSG_HLBSP_ALLOWEMPTYENTITY { FILE *f; char name[_MAX_PATH]; safe_snprintf (name, _MAX_PATH, "%s.hsz", g_Mapname); f = fopen (name, "w"); if (!f) Error("Couldn't open %s", name); float x1,y1,z1; float x2,y2,z2; for (i = 0; i < NUM_HULLS; i++) { x1 = g_hull_size[i][0][0]; y1 = g_hull_size[i][0][1]; z1 = g_hull_size[i][0][2]; x2 = g_hull_size[i][1][0]; y2 = g_hull_size[i][1][1]; z2 = g_hull_size[i][1][2]; fprintf (f, "%g %g %g %g %g %g\n", x1, y1, z1, x2, y2, z2); } fclose (f); } #endif ProcessModels(); Verbose("%5i csg faces\n", c_csgfaces); Verbose("%5i used faces\n", c_outfaces); Verbose("%5i tiny faces\n", c_tiny); Verbose("%5i tiny clips\n", c_tiny_clip); // close hull files for (i = 0; i < NUM_HULLS; i++) { fclose(out[i]); #ifdef ZHLT_DETAILBRUSH fclose (out_detailbrush[i]); #endif #ifdef HLCSG_VIEWSURFACE if (g_viewsurface) { fclose (out_view[i]); } #endif } EmitPlanes(); #ifndef HLCSG_CHART_FIX if (g_chart) PrintBSPFileSizes(); #endif WriteBSP(g_Mapname); // AJM: debug #if 0 Log("\n---------------------------------------\n" "Map Plane Usage:\n" " # normal origin dist type\n" " ( x, y, z) ( x, y, z) ( )\n" ); for (i = 0; i < g_nummapplanes; i++) { plane_t* p = &g_mapplanes[i]; Log( "%3i (%4.0f, %4.0f, %4.0f) (%4.0f, %4.0f, %4.0f) (%5.0f) %i\n", i, p->normal[1], p->normal[2], p->normal[3], p->origin[1], p->origin[2], p->origin[3], p->dist, p->type ); } Log("---------------------------------------\n\n"); #endif // elapsed time end = I_FloatTime(); LogTimeElapsed(end - start); #ifdef ZHLT_PARAMFILE } } #endif return 0; }