mirror of
https://github.com/nzp-team/vhlt.git
synced 2024-11-24 21:02:22 +00:00
1240 lines
36 KiB
C++
1240 lines
36 KiB
C++
#include "csg.h"
|
|
|
|
#define MAXWADNAME 16
|
|
#define MAX_TEXFILES 128
|
|
|
|
// FindMiptex
|
|
// TEX_InitFromWad
|
|
// FindTexture
|
|
// LoadLump
|
|
// AddAnimatingTextures
|
|
|
|
|
|
typedef struct
|
|
{
|
|
char identification[4]; // should be WAD2/WAD3
|
|
int numlumps;
|
|
int infotableofs;
|
|
} wadinfo_t;
|
|
|
|
typedef struct
|
|
{
|
|
int filepos;
|
|
int disksize;
|
|
int size; // uncompressed
|
|
char type;
|
|
char compression;
|
|
char pad1, pad2;
|
|
char name[MAXWADNAME]; // must be null terminated // upper case
|
|
|
|
int iTexFile; // index of the wad this texture is located in
|
|
|
|
} lumpinfo_t;
|
|
|
|
std::deque< std::string > g_WadInclude;
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
std::map< int, bool > s_WadIncludeMap;
|
|
#endif
|
|
|
|
static int nummiptex = 0;
|
|
static lumpinfo_t miptex[MAX_MAP_TEXTURES];
|
|
static int nTexLumps = 0;
|
|
static lumpinfo_t* lumpinfo = NULL;
|
|
static int nTexFiles = 0;
|
|
static FILE* texfiles[MAX_TEXFILES];
|
|
#ifdef HLCSG_AUTOWAD_NEW
|
|
static wadpath_t* texwadpathes[MAX_TEXFILES]; // maps index of the wad to its path
|
|
#endif
|
|
|
|
#ifdef HLCSG_TEXMAP64_FIX
|
|
// The old buggy code in effect limit the number of brush sides to MAX_MAP_BRUSHES
|
|
#ifdef HLCSG_HLBSP_REDUCETEXTURE
|
|
static char *texmap[MAX_INTERNAL_MAP_TEXINFO];
|
|
#else
|
|
static char *texmap[MAX_MAP_TEXINFO];
|
|
#endif
|
|
static int numtexmap = 0;
|
|
|
|
static int texmap_store (char *texname, bool shouldlock = true)
|
|
// This function should never be called unless a new entry in g_texinfo is being allocated.
|
|
{
|
|
int i;
|
|
if (shouldlock)
|
|
{
|
|
ThreadLock ();
|
|
}
|
|
#ifdef HLCSG_HLBSP_REDUCETEXTURE
|
|
hlassume (numtexmap < MAX_INTERNAL_MAP_TEXINFO, assume_MAX_MAP_TEXINFO); // This error should never appear.
|
|
#else
|
|
hlassume (numtexmap < MAX_MAP_TEXINFO, assume_MAX_MAP_TEXINFO); // This error should never appear.
|
|
#endif
|
|
i = numtexmap;
|
|
texmap[numtexmap] = strdup (texname);
|
|
numtexmap++;
|
|
if (shouldlock)
|
|
{
|
|
ThreadUnlock ();
|
|
}
|
|
return i;
|
|
}
|
|
|
|
static char *texmap_retrieve (int index)
|
|
{
|
|
hlassume (0 <= index && index < numtexmap, assume_first);
|
|
return texmap[index];
|
|
}
|
|
|
|
static void texmap_clear ()
|
|
{
|
|
int i;
|
|
ThreadLock ();
|
|
for (i = 0; i < numtexmap; i++)
|
|
{
|
|
free (texmap[i]);
|
|
}
|
|
numtexmap = 0;
|
|
ThreadUnlock ();
|
|
}
|
|
#else
|
|
// fix for 64 bit machines
|
|
#if /* 64 bit */
|
|
static char* texmap64[MAX_MAP_BRUSHES];
|
|
static int tex_max64=0;
|
|
|
|
static inline int texmap64_store(char *texname)
|
|
{
|
|
int curr_tex;
|
|
ThreadLock();
|
|
if (tex_max64 >= MAX_MAP_BRUSHES) // no assert?
|
|
{
|
|
#ifdef ZHLT_CONSOLE
|
|
Error ("MAX_MAP_BRUSHES exceeded!");
|
|
#else
|
|
printf("MAX_MAP_BRUSHES exceeded!\n");
|
|
exit(-1);
|
|
#endif
|
|
}
|
|
curr_tex = tex_max64;
|
|
texmap64[tex_max64] = texname;
|
|
tex_max64++;
|
|
ThreadUnlock();
|
|
return curr_tex;
|
|
}
|
|
|
|
static inline char* texmap64_retrieve( int index)
|
|
{
|
|
if(index > tex_max64)
|
|
{
|
|
#ifdef ZHLT_CONSOLE
|
|
Error ("retrieving bogus texture index %d", index);
|
|
#else
|
|
printf("retrieving bogus texture index %d\n", index);
|
|
exit(-1);
|
|
#endif
|
|
}
|
|
return texmap64[index];
|
|
}
|
|
|
|
#else
|
|
#define texmap64_store( A ) ( (int) A)
|
|
#define texmap64_retrieve( A ) ( (char*) A)
|
|
#endif
|
|
#endif
|
|
|
|
// =====================================================================================
|
|
// CleanupName
|
|
// =====================================================================================
|
|
static void CleanupName(const char* const in, char* out)
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < MAXWADNAME; i++)
|
|
{
|
|
if (!in[i])
|
|
{
|
|
break;
|
|
}
|
|
|
|
out[i] = toupper(in[i]);
|
|
}
|
|
|
|
for (; i < MAXWADNAME; i++)
|
|
{
|
|
out[i] = 0;
|
|
}
|
|
}
|
|
|
|
// =====================================================================================
|
|
// lump_sorters
|
|
// =====================================================================================
|
|
|
|
static int CDECL lump_sorter_by_wad_and_name(const void* lump1, const void* lump2)
|
|
{
|
|
lumpinfo_t* plump1 = (lumpinfo_t*)lump1;
|
|
lumpinfo_t* plump2 = (lumpinfo_t*)lump2;
|
|
|
|
if (plump1->iTexFile == plump2->iTexFile)
|
|
{
|
|
return strcmp(plump1->name, plump2->name);
|
|
}
|
|
else
|
|
{
|
|
return plump1->iTexFile - plump2->iTexFile;
|
|
}
|
|
}
|
|
|
|
static int CDECL lump_sorter_by_name(const void* lump1, const void* lump2)
|
|
{
|
|
lumpinfo_t* plump1 = (lumpinfo_t*)lump1;
|
|
lumpinfo_t* plump2 = (lumpinfo_t*)lump2;
|
|
|
|
return strcmp(plump1->name, plump2->name);
|
|
}
|
|
|
|
// =====================================================================================
|
|
// FindMiptex
|
|
// Find and allocate a texture into the lump data
|
|
// =====================================================================================
|
|
static int FindMiptex(const char* const name)
|
|
{
|
|
int i;
|
|
#ifdef HLCSG_TEXMAP64_FIX
|
|
if (strlen (name) >= MAXWADNAME)
|
|
{
|
|
Error ("Texture name is too long (%s)\n", name);
|
|
}
|
|
#endif
|
|
|
|
ThreadLock();
|
|
for (i = 0; i < nummiptex; i++)
|
|
{
|
|
if (!strcmp(name, miptex[i].name))
|
|
{
|
|
ThreadUnlock();
|
|
return i;
|
|
}
|
|
}
|
|
|
|
hlassume(nummiptex < MAX_MAP_TEXTURES, assume_MAX_MAP_TEXTURES);
|
|
safe_strncpy(miptex[i].name, name, MAXWADNAME);
|
|
nummiptex++;
|
|
ThreadUnlock();
|
|
return i;
|
|
}
|
|
|
|
// =====================================================================================
|
|
// TEX_InitFromWad
|
|
// =====================================================================================
|
|
bool TEX_InitFromWad()
|
|
{
|
|
int i, j;
|
|
wadinfo_t wadinfo;
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
char szTmpWad[1024]; // arbitrary, but needs to be large.
|
|
#endif
|
|
char* pszWadFile;
|
|
const char* pszWadroot;
|
|
wadpath_t* currentwad;
|
|
|
|
Log("\n"); // looks cleaner
|
|
#ifdef HLCSG_AUTOWAD_NEW
|
|
// update wad inclusion
|
|
for (i = 0; i < g_iNumWadPaths; i++)
|
|
{
|
|
currentwad = g_pWadPaths[i];
|
|
if (!g_wadtextures) // '-nowadtextures'
|
|
{
|
|
currentwad->usedbymap = false; // include this wad
|
|
}
|
|
for (WadInclude_i it = g_WadInclude.begin (); it != g_WadInclude.end (); it++) // '-wadinclude xxx.wad'
|
|
{
|
|
if (stristr (currentwad->path, it->c_str ()))
|
|
{
|
|
currentwad->usedbymap = false; // include this wad
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
szTmpWad[0] = 0;
|
|
#endif
|
|
pszWadroot = getenv("WADROOT");
|
|
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
#ifdef HLCSG_AUTOWAD
|
|
autowad_UpdateUsedWads();
|
|
#endif
|
|
#endif
|
|
|
|
// for eachwadpath
|
|
for (i = 0; i < g_iNumWadPaths; i++)
|
|
{
|
|
FILE* texfile; // temporary used in this loop
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
bool bExcludeThisWad = false;
|
|
#endif
|
|
|
|
currentwad = g_pWadPaths[i];
|
|
pszWadFile = currentwad->path;
|
|
|
|
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
#ifdef HLCSG_AUTOWAD
|
|
#ifdef _DEBUG
|
|
Log("[dbg] Attempting to parse wad: '%s'\n", pszWadFile);
|
|
#endif
|
|
|
|
if (g_bWadAutoDetect && !currentwad->usedtextures)
|
|
continue;
|
|
|
|
#ifdef _DEBUG
|
|
Log("[dbg] Parsing wad\n");
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef HLCSG_AUTOWAD_NEW
|
|
texwadpathes[nTexFiles] = currentwad;
|
|
#endif
|
|
texfiles[nTexFiles] = fopen(pszWadFile, "rb");
|
|
|
|
#ifdef SYSTEM_WIN32
|
|
if (!texfiles[nTexFiles])
|
|
{
|
|
// cant find it, maybe this wad file has a hard code drive
|
|
if (pszWadFile[1] == ':')
|
|
{
|
|
pszWadFile += 2; // skip past the drive
|
|
texfiles[nTexFiles] = fopen(pszWadFile, "rb");
|
|
}
|
|
}
|
|
#endif
|
|
|
|
if (!texfiles[nTexFiles] && pszWadroot)
|
|
{
|
|
char szTmp[_MAX_PATH];
|
|
char szFile[_MAX_PATH];
|
|
char szSubdir[_MAX_PATH];
|
|
|
|
ExtractFile(pszWadFile, szFile);
|
|
|
|
ExtractFilePath(pszWadFile, szTmp);
|
|
ExtractFile(szTmp, szSubdir);
|
|
|
|
// szSubdir will have a trailing separator
|
|
safe_snprintf(szTmp, _MAX_PATH, "%s" SYSTEM_SLASH_STR "%s%s", pszWadroot, szSubdir, szFile);
|
|
texfiles[nTexFiles] = fopen(szTmp, "rb");
|
|
|
|
#ifdef SYSTEM_POSIX
|
|
if (!texfiles[nTexFiles])
|
|
{
|
|
// if we cant find it, Convert to lower case and try again
|
|
strlwr(szTmp);
|
|
texfiles[nTexFiles] = fopen(szTmp, "rb");
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#ifdef HLCSG_SEARCHWADPATH_VL
|
|
#ifdef SYSTEM_WIN32
|
|
if (!texfiles[nTexFiles] && pszWadFile[0] == '\\')
|
|
{
|
|
char tmp[_MAX_PATH];
|
|
int l;
|
|
for (l = 'C'; l <= 'Z'; ++l)
|
|
{
|
|
safe_snprintf (tmp, _MAX_PATH, "%c:%s", l, pszWadFile);
|
|
texfiles[nTexFiles] = fopen (tmp, "rb");
|
|
if (texfiles[nTexFiles])
|
|
{
|
|
Developer (DEVELOPER_LEVEL_MESSAGE, "wad file found in drive '%c:' : %s\n", l, pszWadFile);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
if (!texfiles[nTexFiles])
|
|
{
|
|
#ifdef HLCSG_SEARCHWADPATH_VL
|
|
pszWadFile = currentwad->path; // correct it back
|
|
#endif
|
|
// still cant find it, error out
|
|
Fatal(assume_COULD_NOT_FIND_WAD, "Could not open wad file %s", pszWadFile);
|
|
continue;
|
|
}
|
|
|
|
#ifdef HLCSG_WADCFG_NEW
|
|
pszWadFile = currentwad->path; // correct it back
|
|
#endif
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
// look and see if we're supposed to include the textures from this WAD in the bsp.
|
|
WadInclude_i it;
|
|
for (it = g_WadInclude.begin(); it != g_WadInclude.end(); it++)
|
|
{
|
|
if (stristr(pszWadFile, it->c_str()))
|
|
{
|
|
Log("Including Wadfile: %s\n", pszWadFile);
|
|
bExcludeThisWad = true; // wadincluding this one
|
|
s_WadIncludeMap[nTexFiles] = true;
|
|
break;
|
|
}
|
|
}
|
|
#ifdef HLCSG_ONLYENTS_NOWADCHANGE
|
|
if (!bExcludeThisWad && !g_wadtextures) // -nowadtextures
|
|
{
|
|
Log("Including Wadfile: %s\n", pszWadFile);
|
|
bExcludeThisWad = true;
|
|
}
|
|
#endif
|
|
|
|
if (!bExcludeThisWad)
|
|
{
|
|
Log("Using Wadfile: %s\n", pszWadFile);
|
|
#ifdef HLCSG_STRIPWADPATH
|
|
char tmp[_MAX_PATH];
|
|
ExtractFile (pszWadFile, tmp);
|
|
safe_snprintf(szTmpWad, 1024, "%s%s;", szTmpWad, tmp);
|
|
#else
|
|
safe_snprintf(szTmpWad, 1024, "%s%s;", szTmpWad, pszWadFile);
|
|
#endif
|
|
}
|
|
#endif
|
|
|
|
// temp assignment to make things cleaner:
|
|
texfile = texfiles[nTexFiles];
|
|
|
|
// read in this wadfiles information
|
|
SafeRead(texfile, &wadinfo, sizeof(wadinfo));
|
|
|
|
// make sure its a valid format
|
|
if (strncmp(wadinfo.identification, "WAD2", 4) && strncmp(wadinfo.identification, "WAD3", 4))
|
|
{
|
|
Log(" - ");
|
|
Error("%s isn't a Wadfile!", pszWadFile);
|
|
}
|
|
|
|
wadinfo.numlumps = LittleLong(wadinfo.numlumps);
|
|
wadinfo.infotableofs = LittleLong(wadinfo.infotableofs);
|
|
|
|
// read in lump
|
|
if (fseek(texfile, wadinfo.infotableofs, SEEK_SET))
|
|
Warning("fseek to %d in wadfile %s failed\n", wadinfo.infotableofs, pszWadFile);
|
|
|
|
// memalloc for this lump
|
|
lumpinfo = (lumpinfo_t*)realloc(lumpinfo, (nTexLumps + wadinfo.numlumps) * sizeof(lumpinfo_t));
|
|
|
|
// for each texlump
|
|
for (j = 0; j < wadinfo.numlumps; j++, nTexLumps++)
|
|
{
|
|
SafeRead(texfile, &lumpinfo[nTexLumps], (sizeof(lumpinfo_t) - sizeof(int)) ); // iTexFile is NOT read from file
|
|
|
|
if (!TerminatedString(lumpinfo[nTexLumps].name, MAXWADNAME))
|
|
{
|
|
lumpinfo[nTexLumps].name[MAXWADNAME - 1] = 0;
|
|
Log(" - ");
|
|
Warning("Unterminated texture name : wad[%s] texture[%d] name[%s]\n", pszWadFile, nTexLumps, lumpinfo[nTexLumps].name);
|
|
}
|
|
|
|
CleanupName(lumpinfo[nTexLumps].name, lumpinfo[nTexLumps].name);
|
|
|
|
lumpinfo[nTexLumps].filepos = LittleLong(lumpinfo[nTexLumps].filepos);
|
|
lumpinfo[nTexLumps].disksize = LittleLong(lumpinfo[nTexLumps].disksize);
|
|
lumpinfo[nTexLumps].iTexFile = nTexFiles;
|
|
|
|
if (lumpinfo[nTexLumps].disksize > MAX_TEXTURE_SIZE)
|
|
{
|
|
Log(" - ");
|
|
Warning("Larger than expected texture (%d bytes): '%s'",
|
|
lumpinfo[nTexLumps].disksize, lumpinfo[nTexLumps].name);
|
|
}
|
|
|
|
}
|
|
|
|
// AJM: this feature is dependant on autowad. :(
|
|
// CONSIDER: making it standard?
|
|
#ifdef HLCSG_AUTOWAD_NEW
|
|
currentwad->totaltextures = wadinfo.numlumps;
|
|
#else
|
|
#ifdef HLCSG_AUTOWAD
|
|
{
|
|
double percused = ((float)(currentwad->usedtextures) / (float)(g_numUsedTextures)) * 100;
|
|
Log(" - Contains %i used texture%s, %2.2f percent of map (%d textures in wad)\n",
|
|
currentwad->usedtextures, currentwad->usedtextures == 1 ? "" : "s", percused, wadinfo.numlumps);
|
|
}
|
|
#endif
|
|
#endif
|
|
|
|
nTexFiles++;
|
|
hlassume(nTexFiles < MAX_TEXFILES, assume_MAX_TEXFILES);
|
|
}
|
|
|
|
//Log("num of used textures: %i\n", g_numUsedTextures);
|
|
|
|
#ifndef HLCSG_STRIPWADPATH
|
|
// This is absurd. --vluzacn
|
|
// AJM: Tommy suggested i add this warning message in, and it certianly doesnt
|
|
// hurt to be cautious. Especially one of the possible side effects he mentioned was svc_bad
|
|
if (nTexFiles > 8)
|
|
{
|
|
Log("\n");
|
|
Warning("More than 8 wadfiles are in use. (%i)\n"
|
|
"This may be harmless, and if no strange side effects are occurring, then\n"
|
|
"it can safely be ignored. However, if your map starts exhibiting strange\n"
|
|
"or obscure errors, consider this as suspect.\n"
|
|
, nTexFiles);
|
|
}
|
|
#endif
|
|
|
|
// sort texlumps in memory by name
|
|
qsort((void*)lumpinfo, (size_t) nTexLumps, sizeof(lumpinfo[0]), lump_sorter_by_name);
|
|
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
#ifdef HLCSG_CHART_FIX
|
|
Log("\n");
|
|
#ifdef HLCSG_ONLYENTS_NOWADCHANGE
|
|
if (*szTmpWad)
|
|
{
|
|
Log ("Wad files required to run the map: \"%s\"\n", szTmpWad);
|
|
}
|
|
else
|
|
{
|
|
Log ("Wad files required to run the map: (None)\n");
|
|
}
|
|
#else
|
|
Log("\"wad\" is \"%s\"\n", szTmpWad);
|
|
#endif
|
|
#endif
|
|
SetKeyValue(&g_entities[0], "wad", szTmpWad);
|
|
|
|
Log("\n");
|
|
#endif
|
|
CheckFatal();
|
|
return true;
|
|
}
|
|
|
|
// =====================================================================================
|
|
// FindTexture
|
|
// =====================================================================================
|
|
lumpinfo_t* FindTexture(const lumpinfo_t* const source)
|
|
{
|
|
//Log("** PnFNFUNC: FindTexture\n");
|
|
|
|
lumpinfo_t* found = NULL;
|
|
|
|
found = (lumpinfo_t*)bsearch(source, (void*)lumpinfo, (size_t) nTexLumps, sizeof(lumpinfo[0]), lump_sorter_by_name);
|
|
if (!found)
|
|
{
|
|
Warning("::FindTexture() texture %s not found!", source->name);
|
|
if (!strcmp(source->name, "NULL")
|
|
#ifdef HLCSG_PASSBULLETSBRUSH
|
|
|| !strcmp (source->name, "SKIP")
|
|
#endif
|
|
)
|
|
{
|
|
Log("Are you sure you included zhlt.wad in your wadpath list?\n");
|
|
}
|
|
}
|
|
|
|
#ifdef HLCSG_AUTOWAD_NEW
|
|
if (found)
|
|
{
|
|
// get the first and last matching lump
|
|
lumpinfo_t *first = found;
|
|
lumpinfo_t *last = found;
|
|
while (first - 1 >= lumpinfo && lump_sorter_by_name (first - 1, source) == 0)
|
|
{
|
|
first = first - 1;
|
|
}
|
|
while (last + 1 < lumpinfo + nTexLumps && lump_sorter_by_name (last + 1, source) == 0)
|
|
{
|
|
last = last + 1;
|
|
}
|
|
// find the best matching lump
|
|
lumpinfo_t *best = NULL;
|
|
for (found = first; found < last + 1; found++)
|
|
{
|
|
bool better = false;
|
|
if (best == NULL)
|
|
{
|
|
better = true;
|
|
}
|
|
else if (found->iTexFile != best->iTexFile)
|
|
{
|
|
wadpath_t *found_wadpath = texwadpathes[found->iTexFile];
|
|
wadpath_t *best_wadpath = texwadpathes[best->iTexFile];
|
|
if (found_wadpath->usedbymap != best_wadpath->usedbymap)
|
|
{
|
|
better = !found_wadpath->usedbymap; // included wad is better
|
|
}
|
|
else
|
|
{
|
|
better = found->iTexFile < best->iTexFile; // upper in the wad list is better
|
|
}
|
|
}
|
|
else if (found->filepos != best->filepos)
|
|
{
|
|
better = found->filepos < best->filepos; // when there are several lumps with the same name in one wad file
|
|
}
|
|
|
|
if (better)
|
|
{
|
|
best = found;
|
|
}
|
|
}
|
|
found = best;
|
|
}
|
|
#endif
|
|
return found;
|
|
}
|
|
|
|
// =====================================================================================
|
|
// LoadLump
|
|
// =====================================================================================
|
|
int LoadLump(const lumpinfo_t* const source, byte* dest, int* texsize
|
|
#ifdef HLCSG_FILEREADFAILURE_FIX
|
|
, int dest_maxsize
|
|
#endif
|
|
#ifdef ZHLT_NOWADDIR
|
|
, byte *&writewad_data, int &writewad_datasize
|
|
#endif
|
|
)
|
|
{
|
|
#ifdef ZHLT_NOWADDIR
|
|
writewad_data = NULL;
|
|
writewad_datasize = -1;
|
|
#endif
|
|
//Log("** PnFNFUNC: LoadLump\n");
|
|
|
|
*texsize = 0;
|
|
if (source->filepos)
|
|
{
|
|
if (fseek(texfiles[source->iTexFile], source->filepos, SEEK_SET))
|
|
{
|
|
Warning("fseek to %d failed\n", source->filepos);
|
|
#ifdef HLCSG_FILEREADFAILURE_FIX
|
|
Error ("File read failure");
|
|
#endif
|
|
}
|
|
*texsize = source->disksize;
|
|
|
|
#ifdef HLCSG_AUTOWAD_NEW
|
|
if (texwadpathes[source->iTexFile]->usedbymap)
|
|
#else
|
|
bool wadinclude = false;
|
|
std::map< int, bool >::iterator it;
|
|
it = s_WadIncludeMap.find(source->iTexFile);
|
|
if (it != s_WadIncludeMap.end())
|
|
{
|
|
wadinclude = it->second;
|
|
}
|
|
|
|
// Should we just load the texture header w/o the palette & bitmap?
|
|
if (g_wadtextures && !wadinclude)
|
|
#endif
|
|
{
|
|
// Just read the miptex header and zero out the data offsets.
|
|
// We will load the entire texture from the WAD at engine runtime
|
|
int i;
|
|
miptex_t* miptex = (miptex_t*)dest;
|
|
#ifdef HLCSG_FILEREADFAILURE_FIX
|
|
hlassume ((int)sizeof (miptex_t) <= dest_maxsize, assume_MAX_MAP_MIPTEX);
|
|
#endif
|
|
SafeRead(texfiles[source->iTexFile], dest, sizeof(miptex_t));
|
|
|
|
for (i = 0; i < MIPLEVELS; i++)
|
|
miptex->offsets[i] = 0;
|
|
#ifdef ZHLT_NOWADDIR
|
|
writewad_data = (byte *)malloc (source->disksize);
|
|
hlassume (writewad_data != NULL, assume_NoMemory);
|
|
if (fseek (texfiles[source->iTexFile], source->filepos, SEEK_SET))
|
|
Error ("File read failure");
|
|
SafeRead (texfiles[source->iTexFile], writewad_data, source->disksize);
|
|
writewad_datasize = source->disksize;
|
|
#endif
|
|
return sizeof(miptex_t);
|
|
}
|
|
else
|
|
{
|
|
Developer(DEVELOPER_LEVEL_MESSAGE,"Including texture %s\n",source->name);
|
|
// Load the entire texture here so the BSP contains the texture
|
|
#ifdef HLCSG_FILEREADFAILURE_FIX
|
|
hlassume (source->disksize <= dest_maxsize, assume_MAX_MAP_MIPTEX);
|
|
#endif
|
|
SafeRead(texfiles[source->iTexFile], dest, source->disksize);
|
|
return source->disksize;
|
|
}
|
|
}
|
|
|
|
#ifdef HLCSG_ERROR_MISSINGTEXTURE
|
|
Error("::LoadLump() texture %s not found!", source->name);
|
|
#else
|
|
Warning("::LoadLump() texture %s not found!", source->name);
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
// =====================================================================================
|
|
// AddAnimatingTextures
|
|
// =====================================================================================
|
|
void AddAnimatingTextures()
|
|
{
|
|
int base;
|
|
int i, j, k;
|
|
char name[MAXWADNAME];
|
|
|
|
base = nummiptex;
|
|
|
|
for (i = 0; i < base; i++)
|
|
{
|
|
if ((miptex[i].name[0] != '+') && (miptex[i].name[0] != '-'))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
safe_strncpy(name, miptex[i].name, MAXWADNAME);
|
|
|
|
for (j = 0; j < 20; j++)
|
|
{
|
|
if (j < 10)
|
|
{
|
|
name[1] = '0' + j;
|
|
}
|
|
else
|
|
{
|
|
name[1] = 'A' + j - 10; // alternate animation
|
|
}
|
|
|
|
// see if this name exists in the wadfile
|
|
for (k = 0; k < nTexLumps; k++)
|
|
{
|
|
if (!strcmp(name, lumpinfo[k].name))
|
|
{
|
|
FindMiptex(name); // add to the miptex list
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (nummiptex - base)
|
|
{
|
|
Log("added %i additional animating textures.\n", nummiptex - base);
|
|
}
|
|
}
|
|
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
// =====================================================================================
|
|
// GetWadPath
|
|
// AJM: this sub is obsolete
|
|
// =====================================================================================
|
|
char* GetWadPath()
|
|
{
|
|
const char* path = ValueForKey(&g_entities[0], "_wad");
|
|
|
|
if (!path || !path[0])
|
|
{
|
|
path = ValueForKey(&g_entities[0], "wad");
|
|
if (!path || !path[0])
|
|
{
|
|
Warning("no wadfile specified");
|
|
return strdup("");
|
|
}
|
|
}
|
|
|
|
return strdup(path);
|
|
}
|
|
#endif
|
|
|
|
// =====================================================================================
|
|
// WriteMiptex
|
|
// =====================================================================================
|
|
void WriteMiptex()
|
|
{
|
|
int len, texsize, totaltexsize = 0;
|
|
byte* data;
|
|
dmiptexlump_t* l;
|
|
double start, end;
|
|
|
|
g_texdatasize = 0;
|
|
|
|
start = I_FloatTime();
|
|
{
|
|
if (!TEX_InitFromWad())
|
|
return;
|
|
|
|
AddAnimatingTextures();
|
|
}
|
|
end = I_FloatTime();
|
|
Verbose("TEX_InitFromWad & AddAnimatingTextures elapsed time = %ldms\n", (long)(end - start));
|
|
|
|
start = I_FloatTime();
|
|
{
|
|
int i;
|
|
|
|
for (i = 0; i < nummiptex; i++)
|
|
{
|
|
lumpinfo_t* found;
|
|
|
|
found = FindTexture(miptex + i);
|
|
if (found)
|
|
{
|
|
miptex[i] = *found;
|
|
#ifdef HLCSG_AUTOWAD_NEW
|
|
texwadpathes[found->iTexFile]->usedtextures++;
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
miptex[i].iTexFile = miptex[i].filepos = miptex[i].disksize = 0;
|
|
}
|
|
}
|
|
}
|
|
end = I_FloatTime();
|
|
Verbose("FindTextures elapsed time = %ldms\n", (long)(end - start));
|
|
|
|
#ifdef HLCSG_AUTOWAD_NEW
|
|
// Now we have filled lumpinfo for each miptex and the number of used textures for each wad.
|
|
{
|
|
char szTmpWad[MAX_VAL];
|
|
int i;
|
|
|
|
szTmpWad[0] = 0;
|
|
for (i = 0; i < nTexFiles; i++)
|
|
{
|
|
wadpath_t *currentwad = texwadpathes[i];
|
|
if (!currentwad->usedbymap && (currentwad->usedtextures > 0 || !g_bWadAutoDetect))
|
|
{
|
|
Log ("Including Wadfile: %s\n", currentwad->path);
|
|
double percused = (double)currentwad->usedtextures / (double)nummiptex * 100;
|
|
Log (" - Contains %i used texture%s, %2.2f percent of map (%d textures in wad)\n",
|
|
currentwad->usedtextures, currentwad->usedtextures == 1? "": "s", percused, currentwad->totaltextures);
|
|
}
|
|
}
|
|
for (i = 0; i < nTexFiles; i++)
|
|
{
|
|
wadpath_t *currentwad = texwadpathes[i];
|
|
if (currentwad->usedbymap && (currentwad->usedtextures > 0 || !g_bWadAutoDetect))
|
|
{
|
|
Log ("Using Wadfile: %s\n", currentwad->path);
|
|
double percused = (double)currentwad->usedtextures / (double)nummiptex * 100;
|
|
Log (" - Contains %i used texture%s, %2.2f percent of map (%d textures in wad)\n",
|
|
currentwad->usedtextures, currentwad->usedtextures == 1? "": "s", percused, currentwad->totaltextures);
|
|
#ifdef HLCSG_STRIPWADPATH
|
|
char tmp[_MAX_PATH];
|
|
ExtractFile (currentwad->path, tmp);
|
|
safe_strncat (szTmpWad, tmp, MAX_VAL);
|
|
#else
|
|
safe_strncat (szTmpWad, currentwad->path, MAX_VAL);
|
|
#endif
|
|
safe_strncat (szTmpWad, ";", MAX_VAL);
|
|
}
|
|
}
|
|
|
|
#ifdef HLCSG_CHART_FIX
|
|
Log("\n");
|
|
if (*szTmpWad)
|
|
{
|
|
Log ("Wad files required to run the map: \"%s\"\n", szTmpWad);
|
|
}
|
|
else
|
|
{
|
|
Log ("Wad files required to run the map: (None)\n");
|
|
}
|
|
#endif
|
|
SetKeyValue(&g_entities[0], "wad", szTmpWad);
|
|
}
|
|
|
|
#endif
|
|
start = I_FloatTime();
|
|
{
|
|
int i;
|
|
texinfo_t* tx = g_texinfo;
|
|
|
|
// Sort them FIRST by wadfile and THEN by name for most efficient loading in the engine.
|
|
qsort((void*)miptex, (size_t) nummiptex, sizeof(miptex[0]), lump_sorter_by_wad_and_name);
|
|
|
|
// Sleazy Hack 104 Pt 2 - After sorting the miptex array, reset the texinfos to point to the right miptexs
|
|
for (i = 0; i < g_numtexinfo; i++, tx++)
|
|
{
|
|
#ifdef HLCSG_TEXMAP64_FIX
|
|
char* miptex_name = texmap_retrieve(tx->miptex);
|
|
#else
|
|
char* miptex_name = texmap64_retrieve(tx->miptex);
|
|
#endif
|
|
|
|
tx->miptex = FindMiptex(miptex_name);
|
|
|
|
#ifndef HLCSG_TEXMAP64_FIX
|
|
// Free up the originally strdup()'ed miptex_name
|
|
free(miptex_name);
|
|
#endif
|
|
}
|
|
#ifdef HLCSG_TEXMAP64_FIX
|
|
texmap_clear ();
|
|
#endif
|
|
}
|
|
end = I_FloatTime();
|
|
Verbose("qsort(miptex) elapsed time = %ldms\n", (long)(end - start));
|
|
|
|
start = I_FloatTime();
|
|
{
|
|
int i;
|
|
|
|
// Now setup to get the miptex data (or just the headers if using -wadtextures) from the wadfile
|
|
l = (dmiptexlump_t*)g_dtexdata;
|
|
data = (byte*) & l->dataofs[nummiptex];
|
|
l->nummiptex = nummiptex;
|
|
#ifdef ZHLT_NOWADDIR
|
|
char writewad_name[_MAX_PATH];
|
|
FILE *writewad_file;
|
|
int writewad_maxlumpinfos;
|
|
typedef struct
|
|
{
|
|
int filepos;
|
|
int disksize;
|
|
int size;
|
|
char type;
|
|
char compression;
|
|
char pad1, pad2;
|
|
char name[MAXWADNAME];
|
|
} dlumpinfo_t;
|
|
dlumpinfo_t *writewad_lumpinfos;
|
|
wadinfo_t writewad_header;
|
|
safe_snprintf (writewad_name, _MAX_PATH, "%s.wa_", g_Mapname);
|
|
writewad_file = SafeOpenWrite (writewad_name);
|
|
writewad_maxlumpinfos = nummiptex;
|
|
writewad_lumpinfos = (dlumpinfo_t *)malloc (writewad_maxlumpinfos * sizeof (dlumpinfo_t));
|
|
hlassume (writewad_lumpinfos != NULL, assume_NoMemory);
|
|
writewad_header.identification[0] = 'W';
|
|
writewad_header.identification[1] = 'A';
|
|
writewad_header.identification[2] = 'D';
|
|
writewad_header.identification[3] = '3';
|
|
writewad_header.numlumps = 0;
|
|
if (fseek (writewad_file, sizeof (wadinfo_t), SEEK_SET))
|
|
Error ("File write failure");
|
|
#endif
|
|
for (i = 0; i < nummiptex; i++)
|
|
{
|
|
l->dataofs[i] = data - (byte*) l;
|
|
#ifdef ZHLT_NOWADDIR
|
|
byte *writewad_data;
|
|
int writewad_datasize;
|
|
len = LoadLump (miptex + i, data, &texsize
|
|
#ifdef HLCSG_FILEREADFAILURE_FIX
|
|
, &g_dtexdata[g_max_map_miptex] - data
|
|
#endif
|
|
, writewad_data, writewad_datasize);
|
|
if (writewad_data)
|
|
{
|
|
dlumpinfo_t *writewad_lumpinfo = &writewad_lumpinfos[writewad_header.numlumps];
|
|
writewad_lumpinfo->filepos = ftell (writewad_file);
|
|
writewad_lumpinfo->disksize = writewad_datasize;
|
|
writewad_lumpinfo->size = miptex[i].size;
|
|
writewad_lumpinfo->type = miptex[i].type;
|
|
writewad_lumpinfo->compression = miptex[i].compression;
|
|
writewad_lumpinfo->pad1 = miptex[i].pad1;
|
|
writewad_lumpinfo->pad2 = miptex[i].pad2;
|
|
memcpy (writewad_lumpinfo->name, miptex[i].name, MAXWADNAME);
|
|
writewad_header.numlumps++;
|
|
SafeWrite (writewad_file, writewad_data, writewad_datasize);
|
|
free (writewad_data);
|
|
}
|
|
#else
|
|
len = LoadLump(miptex + i, data, &texsize
|
|
#ifdef HLCSG_FILEREADFAILURE_FIX
|
|
, &g_dtexdata[g_max_map_miptex] - data
|
|
#endif
|
|
);
|
|
#endif
|
|
|
|
if (!len)
|
|
{
|
|
l->dataofs[i] = -1; // didn't find the texture
|
|
}
|
|
else
|
|
{
|
|
totaltexsize += texsize;
|
|
|
|
hlassume(totaltexsize < g_max_map_miptex, assume_MAX_MAP_MIPTEX);
|
|
}
|
|
data += len;
|
|
}
|
|
g_texdatasize = data - g_dtexdata;
|
|
#ifdef ZHLT_NOWADDIR
|
|
writewad_header.infotableofs = ftell (writewad_file);
|
|
SafeWrite (writewad_file, writewad_lumpinfos, writewad_header.numlumps * sizeof (dlumpinfo_t));
|
|
if (fseek (writewad_file, 0, SEEK_SET))
|
|
Error ("File write failure");
|
|
SafeWrite (writewad_file, &writewad_header, sizeof (wadinfo_t));
|
|
if (fclose (writewad_file))
|
|
Error ("File write failure");
|
|
#endif
|
|
}
|
|
end = I_FloatTime();
|
|
Log("Texture usage is at %1.2f mb (of %1.2f mb MAX)\n", (float)totaltexsize / (1024 * 1024),
|
|
(float)g_max_map_miptex / (1024 * 1024));
|
|
Verbose("LoadLump() elapsed time = %ldms\n", (long)(end - start));
|
|
}
|
|
|
|
//==========================================================================
|
|
|
|
// =====================================================================================
|
|
// TexinfoForBrushTexture
|
|
// =====================================================================================
|
|
int TexinfoForBrushTexture(const plane_t* const plane, brush_texture_t* bt, const vec3_t origin
|
|
#ifdef ZHLT_HIDDENSOUNDTEXTURE
|
|
, bool shouldhide
|
|
#endif
|
|
)
|
|
{
|
|
vec3_t vecs[2];
|
|
int sv, tv;
|
|
vec_t ang, sinv, cosv;
|
|
vec_t ns, nt;
|
|
texinfo_t tx;
|
|
texinfo_t* tc;
|
|
int i, j, k;
|
|
|
|
#ifdef HLCSG_HLBSP_VOIDTEXINFO
|
|
if (!strncasecmp(bt->name, "NULL", 4))
|
|
{
|
|
return -1;
|
|
}
|
|
#endif
|
|
memset(&tx, 0, sizeof(tx));
|
|
#ifndef HLCSG_CUSTOMHULL
|
|
#ifdef HLCSG_PRECISIONCLIP
|
|
if(!strncmp(bt->name,"BEVEL",5))
|
|
{
|
|
tx.flags |= TEX_BEVEL;
|
|
safe_strncpy(bt->name,"NULL",5);
|
|
}
|
|
#endif
|
|
#endif
|
|
#ifndef HLCSG_AUTOWAD_NEW
|
|
#ifdef HLCSG_AUTOWAD_TEXTURELIST_FIX
|
|
ThreadLock ();
|
|
autowad_PushName (bt->name);
|
|
ThreadUnlock ();
|
|
#endif
|
|
#endif
|
|
#ifdef HLCSG_TEXMAP64_FIX
|
|
FindMiptex (bt->name);
|
|
#else
|
|
tx.miptex = FindMiptex(bt->name);
|
|
|
|
// Note: FindMiptex() still needs to be called here to add it to the global miptex array
|
|
|
|
// Very Sleazy Hack 104 - since the tx.miptex index will be bogus after we sort the miptex array later
|
|
// Put the string name of the miptex in this "index" until after we are done sorting it in WriteMiptex().
|
|
tx.miptex = texmap64_store(strdup(bt->name));
|
|
#endif
|
|
|
|
// set the special flag
|
|
if (bt->name[0] == '*'
|
|
|| !strncasecmp(bt->name, "sky", 3)
|
|
|
|
// =====================================================================================
|
|
//Cpt_Andrew - Env_Sky Check
|
|
// =====================================================================================
|
|
|| !strncasecmp(bt->name, "env_sky", 5)
|
|
// =====================================================================================
|
|
|
|
#ifndef HLCSG_CUSTOMHULL
|
|
|| !strncasecmp(bt->name, "clip", 4)
|
|
#endif
|
|
|| !strncasecmp(bt->name, "origin", 6)
|
|
#ifdef ZHLT_NULLTEX // AJM
|
|
|| !strncasecmp(bt->name, "null", 4)
|
|
#endif
|
|
|| !strncasecmp(bt->name, "aaatrigger", 10)
|
|
)
|
|
{
|
|
// actually only 'sky' and 'aaatrigger' needs this. --vluzacn
|
|
tx.flags |= TEX_SPECIAL;
|
|
}
|
|
#ifdef ZHLT_HIDDENSOUNDTEXTURE
|
|
if (shouldhide)
|
|
{
|
|
tx.flags |= TEX_SHOULDHIDE;
|
|
}
|
|
#endif
|
|
|
|
if (bt->txcommand)
|
|
{
|
|
memcpy(tx.vecs, bt->vects.quark.vects, sizeof(tx.vecs));
|
|
if (origin[0] || origin[1] || origin[2])
|
|
{
|
|
tx.vecs[0][3] += DotProduct(origin, tx.vecs[0]);
|
|
tx.vecs[1][3] += DotProduct(origin, tx.vecs[1]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (g_nMapFileVersion < 220)
|
|
{
|
|
TextureAxisFromPlane(plane, vecs[0], vecs[1]);
|
|
}
|
|
|
|
if (!bt->vects.valve.scale[0])
|
|
{
|
|
bt->vects.valve.scale[0] = 1;
|
|
}
|
|
if (!bt->vects.valve.scale[1])
|
|
{
|
|
bt->vects.valve.scale[1] = 1;
|
|
}
|
|
|
|
if (g_nMapFileVersion < 220)
|
|
{
|
|
// rotate axis
|
|
if (bt->vects.valve.rotate == 0)
|
|
{
|
|
sinv = 0;
|
|
cosv = 1;
|
|
}
|
|
else if (bt->vects.valve.rotate == 90)
|
|
{
|
|
sinv = 1;
|
|
cosv = 0;
|
|
}
|
|
else if (bt->vects.valve.rotate == 180)
|
|
{
|
|
sinv = 0;
|
|
cosv = -1;
|
|
}
|
|
else if (bt->vects.valve.rotate == 270)
|
|
{
|
|
sinv = -1;
|
|
cosv = 0;
|
|
}
|
|
else
|
|
{
|
|
ang = bt->vects.valve.rotate / 180 * Q_PI;
|
|
sinv = sin(ang);
|
|
cosv = cos(ang);
|
|
}
|
|
|
|
if (vecs[0][0])
|
|
{
|
|
sv = 0;
|
|
}
|
|
else if (vecs[0][1])
|
|
{
|
|
sv = 1;
|
|
}
|
|
else
|
|
{
|
|
sv = 2;
|
|
}
|
|
|
|
if (vecs[1][0])
|
|
{
|
|
tv = 0;
|
|
}
|
|
else if (vecs[1][1])
|
|
{
|
|
tv = 1;
|
|
}
|
|
else
|
|
{
|
|
tv = 2;
|
|
}
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
ns = cosv * vecs[i][sv] - sinv * vecs[i][tv];
|
|
nt = sinv * vecs[i][sv] + cosv * vecs[i][tv];
|
|
vecs[i][sv] = ns;
|
|
vecs[i][tv] = nt;
|
|
}
|
|
|
|
for (i = 0; i < 2; i++)
|
|
{
|
|
for (j = 0; j < 3; j++)
|
|
{
|
|
tx.vecs[i][j] = vecs[i][j] / bt->vects.valve.scale[i];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vec_t scale;
|
|
|
|
scale = 1 / bt->vects.valve.scale[0];
|
|
VectorScale(bt->vects.valve.UAxis, scale, tx.vecs[0]);
|
|
|
|
scale = 1 / bt->vects.valve.scale[1];
|
|
VectorScale(bt->vects.valve.VAxis, scale, tx.vecs[1]);
|
|
}
|
|
|
|
tx.vecs[0][3] = bt->vects.valve.shift[0] + DotProduct(origin, tx.vecs[0]);
|
|
tx.vecs[1][3] = bt->vects.valve.shift[1] + DotProduct(origin, tx.vecs[1]);
|
|
}
|
|
|
|
//
|
|
// find the g_texinfo
|
|
//
|
|
ThreadLock();
|
|
tc = g_texinfo;
|
|
for (i = 0; i < g_numtexinfo; i++, tc++)
|
|
{
|
|
// Sleazy hack 104, Pt 3 - Use strcmp on names to avoid dups
|
|
#ifdef HLCSG_TEXMAP64_FIX
|
|
if (strcmp (texmap_retrieve (tc->miptex), bt->name) != 0)
|
|
#else
|
|
if (strcmp(texmap64_retrieve((tc->miptex)), texmap64_retrieve((tx.miptex))) != 0)
|
|
#endif
|
|
{
|
|
continue;
|
|
}
|
|
if (tc->flags != tx.flags)
|
|
{
|
|
continue;
|
|
}
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
for (k = 0; k < 4; k++)
|
|
{
|
|
if (tc->vecs[j][k] != tx.vecs[j][k])
|
|
{
|
|
goto skip;
|
|
}
|
|
}
|
|
}
|
|
ThreadUnlock();
|
|
return i;
|
|
skip:;
|
|
}
|
|
|
|
#ifdef HLCSG_HLBSP_REDUCETEXTURE
|
|
hlassume(g_numtexinfo < MAX_INTERNAL_MAP_TEXINFO, assume_MAX_MAP_TEXINFO);
|
|
#else
|
|
hlassume(g_numtexinfo < MAX_MAP_TEXINFO, assume_MAX_MAP_TEXINFO);
|
|
#endif
|
|
|
|
*tc = tx;
|
|
#ifdef HLCSG_TEXMAP64_FIX
|
|
tc->miptex = texmap_store (bt->name, false);
|
|
#endif
|
|
g_numtexinfo++;
|
|
ThreadUnlock();
|
|
return i;
|
|
}
|
|
|
|
#ifdef HLCSG_HLBSP_VOIDTEXINFO
|
|
// Before WriteMiptex(), for each texinfo in g_texinfo, .miptex is a string rather than texture index, so this function should be used instead of GetTextureByNumber.
|
|
const char *GetTextureByNumber_CSG(int texturenumber)
|
|
{
|
|
if (texturenumber == -1)
|
|
return "";
|
|
#ifdef HLCSG_TEXMAP64_FIX
|
|
return texmap_retrieve (g_texinfo[texturenumber].miptex);
|
|
#else
|
|
return texmap64_retrieve (g_texinfo[texturenumber].miptex);
|
|
#endif
|
|
}
|
|
#endif
|