-/*\r
-Copyright (C) 1999-2007 id Software, Inc. and contributors.\r
-For a list of contributors, see the accompanying CONTRIBUTORS file.\r
-\r
-This file is part of GtkRadiant.\r
-\r
-GtkRadiant is free software; you can redistribute it and/or modify\r
-it under the terms of the GNU General Public License as published by\r
-the Free Software Foundation; either version 2 of the License, or\r
-(at your option) any later version.\r
-\r
-GtkRadiant is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\r
-GNU General Public License for more details.\r
-\r
-You should have received a copy of the GNU General Public License\r
-along with GtkRadiant; if not, write to the Free Software\r
-Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\r
-*/\r
-\r
-// Hydra - FIXME : TTimo, We need to know what game + engine we're using for\r
-// the halflife (not Q2) specific stuff\r
-// we need an API for modules to get this info!\r
-\r
-//\r
-// parses quake3 map format into internal objects\r
-//\r
-\r
-#include "plugin.h"\r
-\r
-// cmdlib\r
-extern void ExtractFileName (const char *path, char *dest);\r
-\r
-extern int g_MapVersion;\r
-int abortcode; // see imap.h for values.\r
-\r
-// Start of half-life specific stuff\r
-\r
-GSList *g_WadList; // halflife specific.\r
-GSList *g_TextureNameCache; // halflife specific.\r
-\r
-// NOTE TTimo: yuck..\r
-void FreeGSList( GSList *l )\r
-{\r
- while (l)\r
- {\r
- free (l->data);\r
- l = g_slist_remove (l, l->data);\r
- }\r
-}\r
-\r
-// NOTE TTimo: ideally, this would be using Str functions instead\r
-void trim( char *str)\r
-{\r
- int len;\r
- len = strlen(str);\r
- while(str[--len] == ' ')\r
- str[len] = 0;\r
-}\r
-\r
-void BuildWadList( char *wadstr )\r
-{\r
- char wads[2048]; // change to CString usage ?\r
- wads[0] = 0;\r
- char *p1,*p2;\r
- char cleanwadname[QER_MAX_NAMELEN];\r
-\r
- g_WadList = NULL;\r
-\r
- strcpy(wads,wadstr);\r
- QE_ConvertDOSToUnixName(wads,wads);\r
-\r
- // ok, we got the list of ; delimited wads, now split it into a GSList that contains\r
- // just the wad names themselves.\r
-\r
- p1 = wads;\r
-\r
- do\r
- {\r
- p2 = strchr(p1,';');\r
- if (p2)\r
- *p2 = 0; // swap the ; with a null terminator\r
-\r
- if (strchr(p1,'/') || strchr(p1,'\\'))\r
- {\r
- ExtractFileName(p1,cleanwadname);\r
-\r
- trim(cleanwadname);\r
-\r
- if (*cleanwadname)\r
- {\r
- g_WadList = g_slist_append (g_WadList, strdup(cleanwadname));\r
- Sys_Printf("wad: %s\n",cleanwadname);\r
- }\r
- }\r
- else\r
- {\r
- trim(p1);\r
- if (*p1)\r
- {\r
- g_WadList = g_slist_append (g_WadList, strdup(p1));\r
- Sys_Printf("wad: %s\n",p1);\r
- }\r
- }\r
- if (p2)\r
- p1 = p2+1; // point back to the remainder of the string\r
- else\r
- p1 = NULL; // make it so we exit the loop.\r
-\r
- } while (p1);\r
-\r
- // strip the ".wad" extensions.\r
- for (GSList *l = g_WadList; l != NULL ; l = l->next)\r
- {\r
- p1 = (char *)l->data;\r
-\r
- if (p1[strlen(p1)-4] == '.')\r
- p1[strlen(p1)-4] = 0;\r
- }\r
-}\r
-\r
-// FIXME: usefulness of this cache sounds very discutable\r
-char *CheckCacheForTextureName( const char *cleantexturename )\r
-{\r
- char *str;\r
- int len;\r
- GSList *l;\r
-\r
- // search our little cache first to speed things up.\r
- // cache strings are stored as "<cleanname>;<actualnameshader>"\r
- len = strlen(cleantexturename);\r
- for (l = g_TextureNameCache; l != NULL ; l = l->next)\r
- {\r
- str = (char *)l->data;\r
- if ((strnicmp(cleantexturename,str,len) == 0) && (str[len] == ';')) // must do in this order or we'll get an access violation, even though it's slower.\r
- {\r
- return (str + len + 1); // skip the delimiter ;\r
- }\r
- }\r
- return NULL;\r
-}\r
-\r
-char *AddToCache(const char *cleantexturename, const char *actualname)\r
-{\r
- char *cachestr;\r
- cachestr = (char *)malloc(strlen(cleantexturename)+1+strlen(actualname)+1); // free()'d when g_TextureNameCache is freed\r
- sprintf(cachestr,"%s;%s",cleantexturename,actualname);\r
- g_TextureNameCache = g_slist_append (g_TextureNameCache, cachestr);\r
- return cachestr;\r
-}\r
-\r
-char *SearchWadsForTextureName( const char *cleantexturename )\r
-{\r
- char *str;\r
- char *wadname;\r
- char *actualtexturename = NULL;\r
- GSList *l;\r
- int count;\r
-\r
- actualtexturename = CheckCacheForTextureName(cleantexturename);\r
- if (actualtexturename)\r
- return actualtexturename;\r
-\r
- // still here ? guess it's not in the cache then!\r
-\r
- // search the wads listed in the worldspawn "wad" key\r
- for (l = g_WadList; l != NULL && actualtexturename == NULL ; l = l->next)\r
- {\r
- wadname = (char *)l->data;\r
-\r
- str = new char[strlen(wadname)+strlen(cleantexturename)+9+1+4+1];\r
-\r
- // hlw here is ok as we never have anything other than hlw files in a wad.\r
- sprintf(str,"textures/%s/%s.hlw",wadname,cleantexturename);\r
- count = vfsGetFileCount(str, VFS_SEARCH_PAK); // only search pack files\r
- // LordHavoc: hacked in .mip loading here\r
- if (!count)\r
- {\r
- sprintf(str,"textures/%s/%s.mip",wadname,cleantexturename);\r
- count = vfsGetFileCount(str, VFS_SEARCH_PAK); // only search pack files\r
- }\r
-\r
- if (count > 0)\r
- {\r
- // strip the extension, build the cache string and add the the cache\r
- str[strlen(str)-4] = 0;\r
-\r
- actualtexturename = AddToCache(cleantexturename,str);\r
-\r
- //point the return value to the actual name, not what we add to the cache\r
- actualtexturename += 1+strlen(cleantexturename);\r
- }\r
- delete [] str;\r
- }\r
- return actualtexturename;\r
-}\r
-// End of half-life specific stuff\r
-\r
-void Patch_Parse(patchMesh_t *pPatch)\r
-{\r
- int i, j;\r
- char *str;\r
-\r
- char *token = Token();\r
-\r
- GetToken(true); //{\r
-\r
- // parse shader name\r
- GetToken(true);\r
- str = new char[strlen(token)+10];\r
- strcpy(str, "textures/");\r
- strcpy(str+9, token);\r
- pPatch->pShader = QERApp_Shader_ForName(str);\r
- pPatch->d_texture = pPatch->pShader->getTexture();\r
- delete [] str;\r
-\r
- GetToken(true); //(\r
-\r
- // parse matrix dimensions\r
- GetToken(false);\r
- pPatch->width = atoi(token);\r
- GetToken(false);\r
- pPatch->height = atoi(token);\r
-\r
- // ignore contents/flags/value\r
- GetToken(false);\r
- GetToken(false);\r
- GetToken(false);\r
-\r
- GetToken(false); //)\r
-\r
- // parse matrix\r
- GetToken(true); //(\r
- for(i=0; i<pPatch->width; i++)\r
- {\r
- GetToken(true); //(\r
- for(j=0; j<pPatch->height; j++)\r
- {\r
- GetToken(false); //(\r
-\r
- GetToken(false);\r
- pPatch->ctrl[i][j].xyz[0] = atof(token);\r
- GetToken(false);\r
- pPatch->ctrl[i][j].xyz[1] = atof(token);\r
- GetToken(false);\r
- pPatch->ctrl[i][j].xyz[2] = atof(token);\r
- GetToken(false);\r
- pPatch->ctrl[i][j].st[0] = atof(token);\r
- GetToken(false);\r
- pPatch->ctrl[i][j].st[1] = atof(token);\r
-\r
- GetToken(false); //)\r
- }\r
- GetToken(false); //)\r
- }\r
- GetToken(true); //)\r
-\r
- GetToken(true); //}\r
-}\r
-\r
-void Face_Parse (face_t *face, bool bAlternateTexdef = false)\r
-{\r
- int i, j;\r
- char *str;\r
- bool bworldcraft = false;\r
-\r
- char *token = Token();\r
-\r
- // parse planepts\r
- str = NULL;\r
- for(i=0; i<3; i++)\r
- {\r
- GetToken(true); //(\r
- for(j=0; j<3; j++)\r
- {\r
- GetToken(false);\r
- face->planepts[i][j] = atof(token);\r
- }\r
- GetToken(false); //)\r
- }\r
-\r
- if(bAlternateTexdef)\r
- {\r
- // parse alternate texdef\r
- GetToken (false); // (\r
- GetToken (false); // (\r
- for (i=0;i<3;i++)\r
- {\r
- GetToken(false);\r
- face->brushprimit_texdef.coords[0][i]=atof(token);\r
- }\r
- GetToken (false); // )\r
- GetToken (false); // (\r
- for (i=0;i<3;i++)\r
- {\r
- GetToken(false);\r
- face->brushprimit_texdef.coords[1][i]=atof(token);\r
- }\r
- GetToken (false); // )\r
- GetToken (false); // )\r
- }\r
-\r
-\r
- // parse shader name\r
- GetToken(false); // shader\r
-\r
- // if we're loading a halflife map then we don't have a relative texture name\r
- // we just get <texturename>. So we need to convert this to a relative name\r
- // like this: "textures/<wadname>/shader", so we use vfsFileFile to get the filename.\r
-\r
- // *** IMPORTANT ***\r
- // For Halflife we need to see if the texture is in wads listed in the\r
- // map's worldspawn "wad" e-pair. If we don't then the image used will be the\r
- // first image with this texture name that is found in any of the wads on the\r
- // user's system. this is not a huge problem, because the map compiler obeys\r
- // the "wad" epair when compiling the map, but the user might end up looking at\r
- // the wrong texture in the editor. (more of a problem if the texture we use\r
- // here has a different size from the one in the wad the map compiler uses...)\r
-\r
- // Hydra: - TTimo: I looked all over for other places to put this, but really it\r
- // is an issue with map loading (because of a limitation of halflife/q2 map format)\r
- // so it's gone in here, it also stops incorrect shader/texdef names getting used\r
- // in the radiant core and it's modules which we'd only have to change later on.\r
- // (either in map_importentities() or the shader module). so it's actually cleaner\r
- // in the long run, even if a little odd. And it keeps more game specific stuff\r
- // OUT of the core, which is a good thing.\r
-\r
- if (g_MapVersion == MAPVERSION_HL)\r
- {\r
- qboolean done = false;\r
-\r
- // FIXME: This bit is halflife specific.\r
- // look in the list of wads supplied in the worldspawn "wad" key/pair for the\r
- // texture first, if it's not in any then we carry on searching the vfs for it\r
- // as usual.\r
-\r
- // each time we find a texture, we add it to the a cache\r
- // so we don't have to hunt the vfs for it each time.\r
- // See SearchWadsForTextureName() and AddToCache() above for cache stuff\r
-\r
- char *wadname;\r
- wadname = SearchWadsForTextureName(token);\r
-\r
- if (wadname)\r
- {\r
- face->texdef.SetName(wadname);\r
- done = true;\r
- }\r
- else\r
- {\r
- // using the cache below means that this message is only ever printed out once!\r
- Sys_Printf("WARNING: could not find \"%s\" in any listed wad files, searching all wad files instead!\n",token);\r
- }\r
- // end of half-life specific bit.\r
-\r
- // check the cache!\r
- if (!done)\r
- {\r
- str = CheckCacheForTextureName(token);\r
- if (str)\r
- {\r
- face->texdef.SetName(str);\r
- done = true;\r
- }\r
- }\r
-\r
- if (!done)\r
- {\r
- char *fullpath;\r
-\r
- str = new char[strlen(token)+4+1];\r
-\r
- // FIXME: halflife specific file extension, we'll have to support Q2/Q1 formats\r
- // and maybe tga texture format for HL here too..\r
- sprintf(str,"%s.hlw",token);\r
- fullpath = vfsGetFullPath(str,0,VFS_SEARCH_PAK | VFS_SEARCH_DIR);\r
-\r
- // MIP support for quake\r
- if (!fullpath)\r
- {\r
- sprintf(str,"%s.mip",token);\r
- fullpath = vfsGetFullPath( str, 0, 0 );\r
- }\r
-\r
- // TGA support in halflife ?\r
- /*\r
- if (!fullpath)\r
- {\r
- sprintf(str,"%s.tga",token);\r
- fullpath = vfsGetFullPath(str);\r
- }\r
- */\r
- delete [] str;\r
-\r
- if (fullpath)\r
- {\r
- // strip the extension.\r
- int len = strlen(fullpath);\r
- if (fullpath[len-4] == '.')\r
- fullpath[len-4] = '\0';\r
-\r
- // and set the correct name!\r
- face->texdef.SetName(fullpath);\r
- AddToCache(token,fullpath);\r
- }\r
- else\r
- {\r
- Sys_Printf("WARNING: could not find \"%s\" in the vfs search path\n",token);\r
- str = new char[strlen(token)+10];\r
- strcpy(str, "textures/");\r
- strcpy(str+9, token);\r
- face->texdef.SetName(str);\r
- AddToCache(token,str);\r
- delete [] str;\r
- }\r
- }\r
- }\r
- else // !MAPVERSION_HL\r
- {\r
- str = new char[strlen(token)+10];\r
- strcpy(str, "textures/");\r
- strcpy(str+9, token);\r
- face->texdef.SetName(str);\r
- delete [] str;\r
- }\r
-\r
- if(!bAlternateTexdef)\r
- {\r
- if (g_MapVersion == MAPVERSION_HL) // Q1 as well ?\r
- {\r
- GetToken(false);\r
- if (token[0] == '[' && token[1] == '\0')\r
- {\r
- bworldcraft = true;\r
-\r
- GetToken(false); // UAxis[0]\r
- GetToken(false); // UAxis[1]\r
- GetToken(false); // UAxis[2]\r
-\r
- GetToken(false); // shift\r
- face->texdef.shift[0] = atof(token);\r
-\r
- GetToken(false); // ]\r
-\r
- GetToken(false); // [\r
- GetToken(false); // VAxis[0]\r
- GetToken(false); // VAxis[1]\r
- GetToken(false); // VAxis[2]\r
-\r
- GetToken(false); // shift\r
- face->texdef.shift[1] = atof(token);\r
-\r
- GetToken(false); // ]\r
-\r
- // rotation is derived from the U and V axes.\r
- // ZHLT ignores this setting even if present in a .map file.\r
- GetToken(false);\r
- face->texdef.rotate = atof(token);\r
-\r
- // Scales\r
- GetToken(false);\r
- face->texdef.scale[0] = atof(token);\r
- GetToken(false);\r
- face->texdef.scale[1] = atof(token);\r
- }\r
- else\r
- {\r
- UnGetToken();\r
- }\r
- }\r
-\r
- if (!bworldcraft) // !MAPVERSION_HL\r
- {\r
- // parse texdef\r
- GetToken(false);\r
- face->texdef.shift[0] = atof(token);\r
- GetToken(false);\r
- face->texdef.shift[1] = atof(token);\r
- GetToken(false);\r
- face->texdef.rotate = atof(token);\r
- GetToken(false);\r
- face->texdef.scale[0] = atof(token);\r
- GetToken(false);\r
- face->texdef.scale[1] = atof(token);\r
- }\r
- }\r
- // parse the optional contents/flags/value\r
- if (!bworldcraft && TokenAvailable())\r
- {\r
- GetToken(true);\r
- if (isdigit(token[0]))\r
- {\r
- face->texdef.contents = atoi(token);\r
- GetToken(false);\r
- face->texdef.flags = atoi(token);\r
- GetToken(false);\r
- face->texdef.value = atoi(token);\r
- }\r
- else\r
- {\r
- UnGetToken();\r
- }\r
- }\r
-}\r
-\r
-bool Primitive_Parse(brush_t *pBrush)\r
-{\r
- char *token = Token();\r
-\r
- GetToken(true);\r
- if (!strcmp(token, "patchDef2"))\r
- {\r
- pBrush->patchBrush = true;\r
- pBrush->pPatch = Patch_Alloc();\r
- pBrush->pPatch->pSymbiot = pBrush;\r
- Patch_Parse(pBrush->pPatch);\r
- GetToken(true); //}\r
-\r
- // A patchdef should never be loaded from a quake2 map file\r
- // so we just return false and the brush+patch gets freed\r
- // and the user gets told.\r
- if (g_MapVersion != MAPVERSION_Q3)\r
- {\r
- // FIXME: Hydra - I wanted to write out a line number here, but I can't because there's no API to access the core's "scriptline" variable.\r
- Syn_Printf("ERROR: patchDef2's are not supported in Quake%d format .map files!\n",g_MapVersion);\r
- abortcode = MAP_WRONGVERSION;\r
- return false;\r
- }\r
- }\r
- else if (!strcmp(token, "brushDef"))\r
- {\r
- pBrush->bBrushDef = true;\r
- GetToken(true); // {\r
- while(1)\r
- {\r
- face_t *f = pBrush->brush_faces;\r
- pBrush->brush_faces = Face_Alloc();\r
- Face_Parse(pBrush->brush_faces, true);\r
- pBrush->brush_faces->next = f;\r
- // check for end of brush\r
- GetToken(true);\r
- if(strcmp(token,"}") == 0)\r
- break;\r
- UnGetToken();\r
- }\r
- GetToken(true); // }\r
- }\r
- else\r
- {\r
- UnGetToken();\r
- while(1)\r
- {\r
- face_t *f = pBrush->brush_faces;\r
- pBrush->brush_faces = Face_Alloc();\r
- Face_Parse(pBrush->brush_faces);\r
- pBrush->brush_faces->next = f;\r
-\r
- // check for end of brush\r
- GetToken(true);\r
- if(strcmp(token,"}") == 0)\r
- break;\r
- UnGetToken();\r
- }\r
- }\r
- return true;\r
-}\r
-\r
-void Entity_Parse(entity_t *pEntity)\r
-{\r
- brush_t *pBrush;\r
- CPtrArray *brushes = NULL;\r
- char temptoken[1024];\r
-\r
- char *token = Token();\r
-\r
- while(1)\r
- {\r
- GetToken(true); // { or } or epair\r
- if (!strcmp(token, "}")) {\r
- break;\r
- } else if(!strcmp(token, "{")) {\r
-\r
- pBrush = Brush_Alloc();\r
- if (Primitive_Parse(pBrush)) {\r
- ((CPtrArray*)pEntity->pData)->Add(pBrush);\r
- } else {\r
- Brush_Free( pBrush, true );\r
- }\r
-\r
- } else {\r
-\r
- strcpy(temptoken, token);\r
- GetToken(false);\r
-\r
- SetKeyValue(pEntity, temptoken, token);\r
-\r
- if (g_MapVersion == MAPVERSION_HL) {\r
- // if we've not god a "wads" key/pair already, then break it into a list.\r
- if (!g_WadList && (stricmp(temptoken,"wad") == 0)) {\r
- BuildWadList(token);\r
- }\r
- }\r
-\r
- }\r
- }\r
-}\r
-\r
-void Map_Read (IDataStream *in, CPtrArray *map)\r
-{\r
- entity_t *pEntity;\r
- char *buf;\r
-\r
- unsigned long len = in->GetLength();\r
- buf = new char[len+1];\r
- in->Read(buf, len);\r
- buf[len] = '\0';\r
- StartTokenParsing(buf);\r
- abortcode = MAP_NOERROR;\r
-\r
- while(abortcode == MAP_NOERROR)\r
- {\r
- if (!GetToken (true)) // { or NULL\r
- break;\r
- pEntity = Entity_Alloc();\r
- pEntity->pData = new CPtrArray;\r
- Entity_Parse(pEntity);\r
- map->Add(pEntity);\r
- }\r
-\r
- delete [] buf;\r
-\r
- if (abortcode != MAP_NOERROR)\r
- {\r
- int num_ents, num_brushes,i,j;\r
- entity_t *e;\r
- CPtrArray *brushes;\r
-\r
- num_ents = map->GetSize();\r
- for(i=0; i<num_ents; i++)\r
- {\r
- e = (entity_t*)map->GetAt(i);\r
- brushes = (CPtrArray*)e->pData;\r
- num_brushes = brushes->GetSize();\r
- for(j=0; j<num_brushes; j++)\r
- {\r
- Brush_Free( (brush_t *)brushes->GetAt(j), true );\r
- }\r
- brushes->RemoveAll();\r
- delete brushes;\r
- Entity_Free(e);\r
- }\r
- map->RemoveAll();\r
- }\r
-}\r
-\r
-void Map_ReadQ3 (IDataStream *in, CPtrArray *map)\r
-{\r
- g_MapVersion = MAPVERSION_Q3;\r
- Map_Read(in,map);\r
-}\r
-\r
-void Map_ReadHL (IDataStream *in, CPtrArray *map)\r
-{\r
- g_WadList = NULL;\r
- g_TextureNameCache = NULL;\r
-\r
- g_MapVersion = MAPVERSION_HL;\r
- Map_Read(in,map);\r
-\r
- FreeGSList(g_TextureNameCache);\r
- FreeGSList(g_WadList);\r
-}\r
-\r
-void Map_ReadQ2 (IDataStream *in, CPtrArray *map)\r
-{\r
- g_MapVersion = MAPVERSION_Q2;\r
- Map_Read(in,map);\r
-}\r
+/*
+Copyright (C) 1999-2007 id Software, Inc. and contributors.
+For a list of contributors, see the accompanying CONTRIBUTORS file.
+
+This file is part of GtkRadiant.
+
+GtkRadiant is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+GtkRadiant is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GtkRadiant; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+// Hydra - FIXME : TTimo, We need to know what game + engine we're using for
+// the halflife (not Q2) specific stuff
+// we need an API for modules to get this info!
+
+//
+// parses quake3 map format into internal objects
+//
+
+#include "plugin.h"
+
+// cmdlib
+extern void ExtractFileName (const char *path, char *dest);
+
+extern int g_MapVersion;
+int abortcode; // see imap.h for values.
+
+// Start of half-life specific stuff
+
+GSList *g_WadList; // halflife specific.
+GSList *g_TextureNameCache; // halflife specific.
+
+// NOTE TTimo: yuck..
+void FreeGSList( GSList *l )
+{
+ while (l)
+ {
+ free (l->data);
+ l = g_slist_remove (l, l->data);
+ }
+}
+
+// NOTE TTimo: ideally, this would be using Str functions instead
+void trim( char *str)
+{
+ int len;
+ len = strlen(str);
+ while(str[--len] == ' ')
+ str[len] = 0;
+}
+
+void BuildWadList( char *wadstr )
+{
+ char wads[2048]; // change to CString usage ?
+ wads[0] = 0;
+ char *p1,*p2;
+ char cleanwadname[QER_MAX_NAMELEN];
+
+ g_WadList = NULL;
+
+ strcpy(wads,wadstr);
+ QE_ConvertDOSToUnixName(wads,wads);
+
+ // ok, we got the list of ; delimited wads, now split it into a GSList that contains
+ // just the wad names themselves.
+
+ p1 = wads;
+
+ do
+ {
+ p2 = strchr(p1,';');
+ if (p2)
+ *p2 = 0; // swap the ; with a null terminator
+
+ if (strchr(p1,'/') || strchr(p1,'\\'))
+ {
+ ExtractFileName(p1,cleanwadname);
+
+ trim(cleanwadname);
+
+ if (*cleanwadname)
+ {
+ g_WadList = g_slist_append (g_WadList, strdup(cleanwadname));
+ Sys_Printf("wad: %s\n",cleanwadname);
+ }
+ }
+ else
+ {
+ trim(p1);
+ if (*p1)
+ {
+ g_WadList = g_slist_append (g_WadList, strdup(p1));
+ Sys_Printf("wad: %s\n",p1);
+ }
+ }
+ if (p2)
+ p1 = p2+1; // point back to the remainder of the string
+ else
+ p1 = NULL; // make it so we exit the loop.
+
+ } while (p1);
+
+ // strip the ".wad" extensions.
+ for (GSList *l = g_WadList; l != NULL ; l = l->next)
+ {
+ p1 = (char *)l->data;
+
+ if (p1[strlen(p1)-4] == '.')
+ p1[strlen(p1)-4] = 0;
+ }
+}
+
+// FIXME: usefulness of this cache sounds very discutable
+char *CheckCacheForTextureName( const char *cleantexturename )
+{
+ char *str;
+ int len;
+ GSList *l;
+
+ // search our little cache first to speed things up.
+ // cache strings are stored as "<cleanname>;<actualnameshader>"
+ len = strlen(cleantexturename);
+ for (l = g_TextureNameCache; l != NULL ; l = l->next)
+ {
+ str = (char *)l->data;
+ if ((strnicmp(cleantexturename,str,len) == 0) && (str[len] == ';')) // must do in this order or we'll get an access violation, even though it's slower.
+ {
+ return (str + len + 1); // skip the delimiter ;
+ }
+ }
+ return NULL;
+}
+
+char *AddToCache(const char *cleantexturename, const char *actualname)
+{
+ char *cachestr;
+ cachestr = (char *)malloc(strlen(cleantexturename)+1+strlen(actualname)+1); // free()'d when g_TextureNameCache is freed
+ sprintf(cachestr,"%s;%s",cleantexturename,actualname);
+ g_TextureNameCache = g_slist_append (g_TextureNameCache, cachestr);
+ return cachestr;
+}
+
+char *SearchWadsForTextureName( const char *cleantexturename )
+{
+ char *str;
+ char *wadname;
+ char *actualtexturename = NULL;
+ GSList *l;
+ int count;
+
+ actualtexturename = CheckCacheForTextureName(cleantexturename);
+ if (actualtexturename)
+ return actualtexturename;
+
+ // still here ? guess it's not in the cache then!
+
+ // search the wads listed in the worldspawn "wad" key
+ for (l = g_WadList; l != NULL && actualtexturename == NULL ; l = l->next)
+ {
+ wadname = (char *)l->data;
+
+ str = new char[strlen(wadname)+strlen(cleantexturename)+9+1+4+1];
+
+ // hlw here is ok as we never have anything other than hlw files in a wad.
+ sprintf(str,"textures/%s/%s.hlw",wadname,cleantexturename);
+ count = vfsGetFileCount(str, VFS_SEARCH_PAK); // only search pack files
+ // LordHavoc: hacked in .mip loading here
+ if (!count)
+ {
+ sprintf(str,"textures/%s/%s.mip",wadname,cleantexturename);
+ count = vfsGetFileCount(str, VFS_SEARCH_PAK); // only search pack files
+ }
+
+ if (count > 0)
+ {
+ // strip the extension, build the cache string and add the the cache
+ str[strlen(str)-4] = 0;
+
+ actualtexturename = AddToCache(cleantexturename,str);
+
+ //point the return value to the actual name, not what we add to the cache
+ actualtexturename += 1+strlen(cleantexturename);
+ }
+ delete [] str;
+ }
+ return actualtexturename;
+}
+// End of half-life specific stuff
+
+void Patch_Parse(patchMesh_t *pPatch)
+{
+ int i, j;
+ char *str;
+
+ char *token = Token();
+
+ GetToken(true); //{
+
+ // parse shader name
+ GetToken(true);
+ str = new char[strlen(token)+10];
+ strcpy(str, "textures/");
+ strcpy(str+9, token);
+ pPatch->pShader = QERApp_Shader_ForName(str);
+ pPatch->d_texture = pPatch->pShader->getTexture();
+ delete [] str;
+
+ GetToken(true); //(
+
+ // parse matrix dimensions
+ GetToken(false);
+ pPatch->width = atoi(token);
+ GetToken(false);
+ pPatch->height = atoi(token);
+
+ // ignore contents/flags/value
+ GetToken(false);
+ GetToken(false);
+ GetToken(false);
+
+ GetToken(false); //)
+
+ // parse matrix
+ GetToken(true); //(
+ for(i=0; i<pPatch->width; i++)
+ {
+ GetToken(true); //(
+ for(j=0; j<pPatch->height; j++)
+ {
+ GetToken(false); //(
+
+ GetToken(false);
+ pPatch->ctrl[i][j].xyz[0] = atof(token);
+ GetToken(false);
+ pPatch->ctrl[i][j].xyz[1] = atof(token);
+ GetToken(false);
+ pPatch->ctrl[i][j].xyz[2] = atof(token);
+ GetToken(false);
+ pPatch->ctrl[i][j].st[0] = atof(token);
+ GetToken(false);
+ pPatch->ctrl[i][j].st[1] = atof(token);
+
+ GetToken(false); //)
+ }
+ GetToken(false); //)
+ }
+ GetToken(true); //)
+
+ GetToken(true); //}
+}
+
+void Face_Parse (face_t *face, bool bAlternateTexdef = false)
+{
+ int i, j;
+ char *str;
+ bool bworldcraft = false;
+
+ char *token = Token();
+
+ // parse planepts
+ str = NULL;
+ for(i=0; i<3; i++)
+ {
+ GetToken(true); //(
+ for(j=0; j<3; j++)
+ {
+ GetToken(false);
+ face->planepts[i][j] = atof(token);
+ }
+ GetToken(false); //)
+ }
+
+ if(bAlternateTexdef)
+ {
+ // parse alternate texdef
+ GetToken (false); // (
+ GetToken (false); // (
+ for (i=0;i<3;i++)
+ {
+ GetToken(false);
+ face->brushprimit_texdef.coords[0][i]=atof(token);
+ }
+ GetToken (false); // )
+ GetToken (false); // (
+ for (i=0;i<3;i++)
+ {
+ GetToken(false);
+ face->brushprimit_texdef.coords[1][i]=atof(token);
+ }
+ GetToken (false); // )
+ GetToken (false); // )
+ }
+
+
+ // parse shader name
+ GetToken(false); // shader
+
+ // if we're loading a halflife map then we don't have a relative texture name
+ // we just get <texturename>. So we need to convert this to a relative name
+ // like this: "textures/<wadname>/shader", so we use vfsFileFile to get the filename.
+
+ // *** IMPORTANT ***
+ // For Halflife we need to see if the texture is in wads listed in the
+ // map's worldspawn "wad" e-pair. If we don't then the image used will be the
+ // first image with this texture name that is found in any of the wads on the
+ // user's system. this is not a huge problem, because the map compiler obeys
+ // the "wad" epair when compiling the map, but the user might end up looking at
+ // the wrong texture in the editor. (more of a problem if the texture we use
+ // here has a different size from the one in the wad the map compiler uses...)
+
+ // Hydra: - TTimo: I looked all over for other places to put this, but really it
+ // is an issue with map loading (because of a limitation of halflife/q2 map format)
+ // so it's gone in here, it also stops incorrect shader/texdef names getting used
+ // in the radiant core and it's modules which we'd only have to change later on.
+ // (either in map_importentities() or the shader module). so it's actually cleaner
+ // in the long run, even if a little odd. And it keeps more game specific stuff
+ // OUT of the core, which is a good thing.
+
+ if (g_MapVersion == MAPVERSION_HL)
+ {
+ qboolean done = false;
+
+ // FIXME: This bit is halflife specific.
+ // look in the list of wads supplied in the worldspawn "wad" key/pair for the
+ // texture first, if it's not in any then we carry on searching the vfs for it
+ // as usual.
+
+ // each time we find a texture, we add it to the a cache
+ // so we don't have to hunt the vfs for it each time.
+ // See SearchWadsForTextureName() and AddToCache() above for cache stuff
+
+ char *wadname;
+ wadname = SearchWadsForTextureName(token);
+
+ if (wadname)
+ {
+ face->texdef.SetName(wadname);
+ done = true;
+ }
+ else
+ {
+ // using the cache below means that this message is only ever printed out once!
+ Sys_Printf("WARNING: could not find \"%s\" in any listed wad files, searching all wad files instead!\n",token);
+ }
+ // end of half-life specific bit.
+
+ // check the cache!
+ if (!done)
+ {
+ str = CheckCacheForTextureName(token);
+ if (str)
+ {
+ face->texdef.SetName(str);
+ done = true;
+ }
+ }
+
+ if (!done)
+ {
+ char *fullpath;
+
+ str = new char[strlen(token)+4+1];
+
+ // FIXME: halflife specific file extension, we'll have to support Q2/Q1 formats
+ // and maybe tga texture format for HL here too..
+ sprintf(str,"%s.hlw",token);
+ fullpath = vfsGetFullPath(str,0,VFS_SEARCH_PAK | VFS_SEARCH_DIR);
+
+ // MIP support for quake
+ if (!fullpath)
+ {
+ sprintf(str,"%s.mip",token);
+ fullpath = vfsGetFullPath( str, 0, 0 );
+ }
+
+ // TGA support in halflife ?
+ /*
+ if (!fullpath)
+ {
+ sprintf(str,"%s.tga",token);
+ fullpath = vfsGetFullPath(str);
+ }
+ */
+ delete [] str;
+
+ if (fullpath)
+ {
+ // strip the extension.
+ int len = strlen(fullpath);
+ if (fullpath[len-4] == '.')
+ fullpath[len-4] = '\0';
+
+ // and set the correct name!
+ face->texdef.SetName(fullpath);
+ AddToCache(token,fullpath);
+ }
+ else
+ {
+ Sys_Printf("WARNING: could not find \"%s\" in the vfs search path\n",token);
+ str = new char[strlen(token)+10];
+ strcpy(str, "textures/");
+ strcpy(str+9, token);
+ face->texdef.SetName(str);
+ AddToCache(token,str);
+ delete [] str;
+ }
+ }
+ }
+ else // !MAPVERSION_HL
+ {
+ str = new char[strlen(token)+10];
+ strcpy(str, "textures/");
+ strcpy(str+9, token);
+ face->texdef.SetName(str);
+ delete [] str;
+ }
+
+ if(!bAlternateTexdef)
+ {
+ if (g_MapVersion == MAPVERSION_HL) // Q1 as well ?
+ {
+ GetToken(false);
+ if (token[0] == '[' && token[1] == '\0')
+ {
+ bworldcraft = true;
+
+ GetToken(false); // UAxis[0]
+ GetToken(false); // UAxis[1]
+ GetToken(false); // UAxis[2]
+
+ GetToken(false); // shift
+ face->texdef.shift[0] = atof(token);
+
+ GetToken(false); // ]
+
+ GetToken(false); // [
+ GetToken(false); // VAxis[0]
+ GetToken(false); // VAxis[1]
+ GetToken(false); // VAxis[2]
+
+ GetToken(false); // shift
+ face->texdef.shift[1] = atof(token);
+
+ GetToken(false); // ]
+
+ // rotation is derived from the U and V axes.
+ // ZHLT ignores this setting even if present in a .map file.
+ GetToken(false);
+ face->texdef.rotate = atof(token);
+
+ // Scales
+ GetToken(false);
+ face->texdef.scale[0] = atof(token);
+ GetToken(false);
+ face->texdef.scale[1] = atof(token);
+ }
+ else
+ {
+ UnGetToken();
+ }
+ }
+
+ if (!bworldcraft) // !MAPVERSION_HL
+ {
+ // parse texdef
+ GetToken(false);
+ face->texdef.shift[0] = atof(token);
+ GetToken(false);
+ face->texdef.shift[1] = atof(token);
+ GetToken(false);
+ face->texdef.rotate = atof(token);
+ GetToken(false);
+ face->texdef.scale[0] = atof(token);
+ GetToken(false);
+ face->texdef.scale[1] = atof(token);
+ }
+ }
+ // parse the optional contents/flags/value
+ if (!bworldcraft && TokenAvailable())
+ {
+ GetToken(true);
+ if (isdigit(token[0]))
+ {
+ face->texdef.contents = atoi(token);
+ GetToken(false);
+ face->texdef.flags = atoi(token);
+ GetToken(false);
+ face->texdef.value = atoi(token);
+ }
+ else
+ {
+ UnGetToken();
+ }
+ }
+}
+
+bool Primitive_Parse(brush_t *pBrush)
+{
+ char *token = Token();
+
+ GetToken(true);
+ if (!strcmp(token, "patchDef2"))
+ {
+ pBrush->patchBrush = true;
+ pBrush->pPatch = Patch_Alloc();
+ pBrush->pPatch->pSymbiot = pBrush;
+ Patch_Parse(pBrush->pPatch);
+ GetToken(true); //}
+
+ // A patchdef should never be loaded from a quake2 map file
+ // so we just return false and the brush+patch gets freed
+ // and the user gets told.
+ if (g_MapVersion != MAPVERSION_Q3)
+ {
+ // FIXME: Hydra - I wanted to write out a line number here, but I can't because there's no API to access the core's "scriptline" variable.
+ Syn_Printf("ERROR: patchDef2's are not supported in Quake%d format .map files!\n",g_MapVersion);
+ abortcode = MAP_WRONGVERSION;
+ return false;
+ }
+ }
+ else if (!strcmp(token, "brushDef"))
+ {
+ pBrush->bBrushDef = true;
+ GetToken(true); // {
+ while(1)
+ {
+ face_t *f = pBrush->brush_faces;
+ pBrush->brush_faces = Face_Alloc();
+ Face_Parse(pBrush->brush_faces, true);
+ pBrush->brush_faces->next = f;
+ // check for end of brush
+ GetToken(true);
+ if(strcmp(token,"}") == 0)
+ break;
+ UnGetToken();
+ }
+ GetToken(true); // }
+ }
+ else
+ {
+ UnGetToken();
+ while(1)
+ {
+ face_t *f = pBrush->brush_faces;
+ pBrush->brush_faces = Face_Alloc();
+ Face_Parse(pBrush->brush_faces);
+ pBrush->brush_faces->next = f;
+
+ // check for end of brush
+ GetToken(true);
+ if(strcmp(token,"}") == 0)
+ break;
+ UnGetToken();
+ }
+ }
+ return true;
+}
+
+void Entity_Parse(entity_t *pEntity)
+{
+ brush_t *pBrush;
+ CPtrArray *brushes = NULL;
+ char temptoken[1024];
+
+ char *token = Token();
+
+ while(1)
+ {
+ GetToken(true); // { or } or epair
+ if (!strcmp(token, "}")) {
+ break;
+ } else if(!strcmp(token, "{")) {
+
+ pBrush = Brush_Alloc();
+ if (Primitive_Parse(pBrush)) {
+ ((CPtrArray*)pEntity->pData)->Add(pBrush);
+ } else {
+ Brush_Free( pBrush, true );
+ }
+
+ } else {
+
+ strcpy(temptoken, token);
+ GetToken(false);
+
+ SetKeyValue(pEntity, temptoken, token);
+
+ if (g_MapVersion == MAPVERSION_HL) {
+ // if we've not god a "wads" key/pair already, then break it into a list.
+ if (!g_WadList && (stricmp(temptoken,"wad") == 0)) {
+ BuildWadList(token);
+ }
+ }
+
+ }
+ }
+}
+
+void Map_Read (IDataStream *in, CPtrArray *map)
+{
+ entity_t *pEntity;
+ char *buf;
+
+ unsigned long len = in->GetLength();
+ buf = new char[len+1];
+ in->Read(buf, len);
+ buf[len] = '\0';
+ StartTokenParsing(buf);
+ abortcode = MAP_NOERROR;
+
+ while(abortcode == MAP_NOERROR)
+ {
+ if (!GetToken (true)) // { or NULL
+ break;
+ pEntity = Entity_Alloc();
+ pEntity->pData = new CPtrArray;
+ Entity_Parse(pEntity);
+ map->Add(pEntity);
+ }
+
+ delete [] buf;
+
+ if (abortcode != MAP_NOERROR)
+ {
+ int num_ents, num_brushes,i,j;
+ entity_t *e;
+ CPtrArray *brushes;
+
+ num_ents = map->GetSize();
+ for(i=0; i<num_ents; i++)
+ {
+ e = (entity_t*)map->GetAt(i);
+ brushes = (CPtrArray*)e->pData;
+ num_brushes = brushes->GetSize();
+ for(j=0; j<num_brushes; j++)
+ {
+ Brush_Free( (brush_t *)brushes->GetAt(j), true );
+ }
+ brushes->RemoveAll();
+ delete brushes;
+ Entity_Free(e);
+ }
+ map->RemoveAll();
+ }
+}
+
+void Map_ReadQ3 (IDataStream *in, CPtrArray *map)
+{
+ g_MapVersion = MAPVERSION_Q3;
+ Map_Read(in,map);
+}
+
+void Map_ReadHL (IDataStream *in, CPtrArray *map)
+{
+ g_WadList = NULL;
+ g_TextureNameCache = NULL;
+
+ g_MapVersion = MAPVERSION_HL;
+ Map_Read(in,map);
+
+ FreeGSList(g_TextureNameCache);
+ FreeGSList(g_WadList);
+}
+
+void Map_ReadQ2 (IDataStream *in, CPtrArray *map)
+{
+ g_MapVersion = MAPVERSION_Q2;
+ Map_Read(in,map);
+}