Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

QE3.CPP (14574B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 #include "stdafx.h"
     23 #include "qe3.h"
     24 #include "PrefsDlg.h"
     25 #include <direct.h>  
     26 #include <sys\stat.h> 
     27 
     28 QEGlobals_t  g_qeglobals;
     29 
     30 void WINAPI QE_CheckOpenGLForErrors(void)
     31 {
     32   CString strMsg;
     33   int i = qglGetError();
     34   if (i != GL_NO_ERROR)
     35   {
     36     if (i == GL_OUT_OF_MEMORY)
     37     {
     38       //strMsg.Format("OpenGL out of memory error %s\nDo you wish to save before exiting?", qgluErrorString((GLenum)i));
     39       if (MessageBox(g_qeglobals.d_hwndMain, strMsg, "Q3Radiant Error", MB_YESNO) == IDYES)
     40       {
     41         Map_SaveFile(NULL, false);
     42       }
     43 		  exit(1);
     44     }
     45     else
     46     {
     47       //strMsg.Format("Warning: OpenGL Error %s\n ", qgluErrorString((GLenum)i));
     48 		  Sys_Printf (strMsg.GetBuffer(0));
     49     }
     50   }
     51 }
     52 
     53 
     54 char *ExpandReletivePath (char *p)
     55 {
     56 	static char	temp[1024];
     57 	char	*base;
     58 
     59 	if (!p || !p[0])
     60 		return NULL;
     61 	if (p[0] == '/' || p[0] == '\\')
     62 		return p;
     63 
     64 	base = ValueForKey(g_qeglobals.d_project_entity, "basepath");
     65 	sprintf (temp, "%s/%s", base, p);
     66 	return temp;
     67 }
     68 
     69 char *copystring (char *s)
     70 {
     71 	char	*b;
     72 	b = (char*)malloc(strlen(s)+1);
     73 	strcpy (b,s);
     74 	return b;
     75 }
     76 
     77 
     78 bool DoesFileExist(const char* pBuff, long& lSize)
     79 {
     80   CFile file;
     81   if (file.Open(pBuff, CFile::modeRead | CFile::shareDenyNone))
     82   {
     83     lSize += file.GetLength();
     84     file.Close();
     85     return true;
     86   }
     87   return false;
     88 }
     89 
     90 
     91 void Map_Snapshot()
     92 {
     93   CString strMsg;
     94   // we need to do the following
     95   // 1. make sure the snapshot directory exists (create it if it doesn't)
     96   // 2. find out what the lastest save is based on number
     97   // 3. inc that and save the map
     98   CString strOrgPath, strOrgFile;
     99   ExtractPath_and_Filename(currentmap, strOrgPath, strOrgFile);
    100   AddSlash(strOrgPath);
    101   strOrgPath += "snapshots";
    102   bool bGo = true;
    103   struct _stat Stat;
    104   if (_stat(strOrgPath, &Stat) == -1)
    105   {
    106     bGo = (_mkdir(strOrgPath) != -1);
    107   }
    108   AddSlash(strOrgPath);
    109   if (bGo)
    110   {
    111     int nCount = 0;
    112     long lSize = 0;
    113     CString strNewPath = strOrgPath;
    114     strNewPath += strOrgFile;
    115     CString strFile;
    116     while (bGo)
    117     {
    118       strFile.Format("%s.%i", strNewPath, nCount);
    119       bGo = DoesFileExist(strFile, lSize);
    120       nCount++;
    121     }
    122     // strFile has the next available slot
    123     Map_SaveFile(strFile.GetBuffer(0), false);
    124 		Sys_SetTitle (currentmap);
    125     if (lSize > 12 * 1024 * 1024) // total size of saves > 4 mb
    126     {
    127       Sys_Printf("The snapshot files in the [%s] directory total more than 4 megabytes. You might consider cleaning the directory up.", strOrgPath);
    128     }
    129   }
    130   else
    131   {
    132     strMsg.Format("Snapshot save failed.. unabled to create directory\n%s", strOrgPath);
    133     g_pParentWnd->MessageBox(strMsg);
    134   }
    135 }
    136 /*
    137 ===============
    138 QE_CheckAutoSave
    139 
    140 If five minutes have passed since making a change
    141 and the map hasn't been saved, save it out.
    142 ===============
    143 */
    144 
    145 
    146 void QE_CheckAutoSave( void )
    147 {
    148 	static clock_t s_start;
    149 	clock_t        now;
    150 
    151 	now = clock();
    152 
    153 	if ( modified != 1 || !s_start)
    154 	{
    155 		s_start = now;
    156 		return;
    157 	}
    158 
    159 	if ( now - s_start > ( CLOCKS_PER_SEC * 60 * g_PrefsDlg.m_nAutoSave))
    160 	{
    161 
    162     if (g_PrefsDlg.m_bAutoSave)
    163     {
    164       CString strMsg = g_PrefsDlg.m_bSnapShots ? "Autosaving snapshot..." : "Autosaving...";
    165 		  Sys_Printf(strMsg.GetBuffer(0));
    166       Sys_Printf("\n");
    167 		  Sys_Status (strMsg.GetBuffer(0),0);
    168 
    169       // only snapshot if not working on a default map
    170       if (g_PrefsDlg.m_bSnapShots && stricmp(currentmap, "unnamed.map") != 0)
    171       {
    172         Map_Snapshot();
    173       }
    174       else
    175       {
    176 		    Map_SaveFile (ValueForKey(g_qeglobals.d_project_entity, "autosave"), false);
    177       }
    178 
    179 		  Sys_Status ("Autosaving...Saved.", 0 );
    180 		  modified = 2;
    181     }
    182     else
    183     {
    184 		  Sys_Printf ("Autosave skipped...\n");
    185 		  Sys_Status ("Autosave skipped...", 0 );
    186     }
    187 		s_start = now;
    188 	}
    189 }
    190 
    191 
    192 int BuildShortPathName(const char* pPath, char* pBuffer, int nBufferLen)
    193 {
    194   char *pFile = NULL;
    195   int nResult = GetFullPathName(pPath, nBufferLen, pBuffer, &pFile); 
    196   nResult = GetShortPathName(pPath, pBuffer, nBufferLen);
    197   if (nResult == 0)
    198     strcpy(pBuffer, pPath);                     // Use long filename
    199   return nResult;
    200 }
    201 
    202 
    203 
    204 const char *g_pPathFixups[]=
    205 {
    206   "basepath",
    207   "remotebasepath",
    208   "entitypath",
    209   "texturepath",
    210   "autosave",
    211   "mapspath"
    212 };
    213 
    214 const int g_nPathFixupCount = sizeof(g_pPathFixups) / sizeof(const char*);
    215 
    216 /*
    217 ===========
    218 QE_LoadProject
    219 ===========
    220 */
    221 qboolean QE_LoadProject (char *projectfile)
    222 {
    223 	char	*data;
    224 
    225 	Sys_Printf ("QE_LoadProject (%s)\n", projectfile);
    226 	
    227 	if ( LoadFileNoCrash (projectfile, (void **)&data) == -1)
    228 		return false;
    229 	
    230 	g_strProject = projectfile;
    231 	
    232 	CString strData = data;
    233 	free(data);
    234 	
    235 	CString strQ2Path = g_PrefsDlg.m_strQuake2;
    236 	CString strQ2File;
    237 	ExtractPath_and_Filename(g_PrefsDlg.m_strQuake2, strQ2Path, strQ2File);
    238 	AddSlash(strQ2Path);
    239 	
    240 	
    241 	char* pBuff = new char[1024];
    242 	
    243 	BuildShortPathName(strQ2Path, pBuff, 1024);
    244 	FindReplace(strData, "__Q2PATH", pBuff);
    245 	BuildShortPathName(g_strAppPath, pBuff, 1024);
    246 	FindReplace(strData, "__QERPATH", pBuff);
    247 	
    248 	char* pFile;
    249 	if (GetFullPathName(projectfile, 1024, pBuff, &pFile))
    250 	{
    251 		g_PrefsDlg.m_strLastProject = pBuff;
    252 		BuildShortPathName(g_PrefsDlg.m_strLastProject, pBuff, 1024);
    253 		g_PrefsDlg.m_strLastProject = pBuff;
    254 		g_PrefsDlg.SavePrefs();
    255 		
    256 		ExtractPath_and_Filename(pBuff, strQ2Path, strQ2File);
    257 		int nLen = strQ2Path.GetLength();
    258 		if (nLen > 0)
    259 		{
    260 			if (strQ2Path[nLen - 1] == '\\')
    261 				strQ2Path.SetAt(nLen-1,'\0');
    262 			char* pBuffer = strQ2Path.GetBufferSetLength(_MAX_PATH + 1);
    263 			int n = strQ2Path.ReverseFind('\\');
    264 			if (n >=0 )
    265 				pBuffer[n + 1] = '\0';
    266 			strQ2Path.ReleaseBuffer();
    267 			FindReplace(strData, "__QEPROJPATH", strQ2Path);
    268 		}
    269 	}
    270 	
    271 	
    272 	StartTokenParsing (strData.GetBuffer(0));
    273 	g_qeglobals.d_project_entity = Entity_Parse (true);
    274 	if (!g_qeglobals.d_project_entity)
    275 		Error ("Couldn't parse %s", projectfile);
    276 
    277   for (int i = 0; i < g_nPathFixupCount; i++)
    278   {
    279     char *pPath = ValueForKey (g_qeglobals.d_project_entity, g_pPathFixups[i]);
    280     if (pPath[0] != '\\' && pPath[0] != '/')
    281     {
    282 	    if (GetFullPathName(pPath, 1024, pBuff, &pFile))
    283       {
    284         SetKeyValue(g_qeglobals.d_project_entity, g_pPathFixups[i], pBuff);
    285       }
    286     }
    287   }
    288 
    289 	delete []pBuff;
    290 
    291 	// set here some default project settings you need
    292 	if ( strlen( ValueForKey( g_qeglobals.d_project_entity, "brush_primit" ) ) == 0 )
    293 	{
    294 		SetKeyValue( g_qeglobals.d_project_entity, "brush_primit", "0" );
    295 	}
    296 
    297 	g_qeglobals.m_bBrushPrimitMode = IntForKey( g_qeglobals.d_project_entity, "brush_primit" );
    298 
    299 
    300 	Eclass_InitForSourceDirectory (ValueForKey (g_qeglobals.d_project_entity, "entitypath"));
    301 	FillClassList();		// list in entity window
    302 	
    303 	Map_New();
    304 	
    305 	
    306 	FillTextureMenu();
    307 	FillBSPMenu();
    308 	
    309 	return true;
    310 }
    311 
    312 /*
    313 ===========
    314 QE_SaveProject
    315 ===========
    316 */
    317 //extern char	*bsp_commands[256];
    318 
    319 qboolean QE_SaveProject (const char* pProjectFile)
    320 {
    321 	//char	filename[1024];
    322 	FILE	*fp;
    323 	epair_t	*ep;
    324 
    325 	//sprintf (filename, "%s\\%s.prj", g_projectdir, g_username);
    326 
    327 	if (!(fp = fopen (pProjectFile, "w+")))
    328 		Error ("Could not open project file!");
    329 	
    330 	fprintf (fp, "{\n");
    331 	for (ep = g_qeglobals.d_project_entity->epairs; ep; ep=ep->next)
    332 		fprintf (fp, "\"%s\" \"%s\"\n", ep->key, ep->value);
    333 	fprintf (fp, "}\n");
    334 
    335 	fclose (fp);
    336 	
    337 	return TRUE;
    338 }
    339 
    340 
    341 
    342 /*
    343 ===========
    344 QE_KeyDown
    345 ===========
    346 */
    347 #define	SPEED_MOVE	32
    348 #define	SPEED_TURN	22.5
    349 
    350 
    351 /*
    352 ===============
    353 ConnectEntities
    354 
    355 Sets target / targetname on the two entities selected
    356 from the first selected to the secon
    357 ===============
    358 */
    359 void ConnectEntities (void)
    360 {
    361 	entity_t	*e1, *e2, *e;
    362 	char		*target, *tn;
    363 	int			maxtarg, targetnum;
    364 	char		newtarg[32];
    365 
    366 	if (g_qeglobals.d_select_count != 2)
    367 	{
    368 		Sys_Status ("Must have two brushes selected.", 0);
    369 		Sys_Beep ();
    370 		return;
    371 	}
    372 
    373 	e1 = g_qeglobals.d_select_order[0]->owner;
    374 	e2 = g_qeglobals.d_select_order[1]->owner;
    375 
    376 	if (e1 == world_entity || e2 == world_entity)
    377 	{
    378 		Sys_Status ("Can't connect to the world.", 0);
    379 		Sys_Beep ();
    380 		return;
    381 	}
    382 
    383 	if (e1 == e2)
    384 	{
    385 		Sys_Status ("Brushes are from same entity.", 0);
    386 		Sys_Beep ();
    387 		return;
    388 	}
    389 
    390 	target = ValueForKey (e1, "target");
    391 	if (target && target[0])
    392 		strcpy (newtarg, target);
    393 	else
    394 	{
    395 		target = ValueForKey (e2, "targetname");
    396 		if (target && target[0])
    397 			strcpy (newtarg, target);
    398 		else
    399 		{
    400 			// make a unique target value
    401 			maxtarg = 0;
    402 			for (e=entities.next ; e != &entities ; e=e->next)
    403 			{
    404 				tn = ValueForKey (e, "targetname");
    405 				if (tn && tn[0])
    406 				{
    407 					targetnum = atoi(tn+1);
    408 					if (targetnum > maxtarg)
    409 						maxtarg = targetnum;
    410 				}
    411 			}
    412 			sprintf (newtarg, "t%i", maxtarg+1);
    413 		}
    414 	}
    415 
    416 	SetKeyValue (e1, "target", newtarg);
    417 	SetKeyValue (e2, "targetname", newtarg);
    418 	Sys_UpdateWindows (W_XY | W_CAMERA);
    419 
    420 	Select_Deselect();
    421 	Select_Brush (g_qeglobals.d_select_order[1]);
    422 }
    423 
    424 qboolean QE_SingleBrush (bool bQuiet)
    425 {
    426 	if ( (selected_brushes.next == &selected_brushes)
    427 		|| (selected_brushes.next->next != &selected_brushes) )
    428 	{
    429 	  if (!bQuiet)
    430     {
    431 	  	Sys_Printf ("Error: you must have a single brush selected\n");
    432 	  }
    433 		return false;
    434 	}
    435 	if (selected_brushes.next->owner->eclass->fixedsize)
    436 	{
    437 	  if (!bQuiet)
    438 	  {
    439 		  Sys_Printf ("Error: you cannot manipulate fixed size entities\n");
    440 	  }
    441 		return false;
    442 	}
    443 
    444 	return true;
    445 }
    446 
    447 void QE_Init (void)
    448 {
    449 	/*
    450 	** initialize variables
    451 	*/
    452 	g_qeglobals.d_gridsize = 8;
    453 	g_qeglobals.d_showgrid = true;
    454 
    455 	/*
    456 	** other stuff
    457 	*/
    458 	Texture_Init (true);
    459 	//Cam_Init ();
    460 	//XY_Init ();
    461 	Z_Init ();
    462 	Terrain_Init();
    463 }
    464 
    465 void WINAPI QE_ConvertDOSToUnixName( char *dst, const char *src )
    466 {
    467 	while ( *src )
    468 	{
    469 		if ( *src == '\\' )
    470 			*dst = '/';
    471 		else
    472 			*dst = *src;
    473 		dst++; src++;
    474 	}
    475 	*dst = 0;
    476 }
    477 
    478 int g_numbrushes, g_numentities;
    479 
    480 void QE_CountBrushesAndUpdateStatusBar( void )
    481 {
    482 	static int      s_lastbrushcount, s_lastentitycount;
    483 	static qboolean s_didonce;
    484 	
    485 	//entity_t   *e;
    486 	brush_t	   *b, *next;
    487 
    488 	g_numbrushes = 0;
    489 	g_numentities = 0;
    490 	
    491 	if ( active_brushes.next != NULL )
    492 	{
    493 		for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next)
    494 		{
    495 			next = b->next;
    496 			if (b->brush_faces )
    497 			{
    498 				if ( !b->owner->eclass->fixedsize)
    499 					g_numbrushes++;
    500 				else
    501 					g_numentities++;
    502 			}
    503 		}
    504 	}
    505 /*
    506 	if ( entities.next != NULL )
    507 	{
    508 		for ( e = entities.next ; e != &entities && g_numentities != MAX_MAP_ENTITIES ; e = e->next)
    509 		{
    510 			g_numentities++;
    511 		}
    512 	}
    513 */
    514 	if ( ( ( g_numbrushes != s_lastbrushcount ) || ( g_numentities != s_lastentitycount ) ) || ( !s_didonce ) )
    515 	{
    516 		Sys_UpdateStatusBar();
    517 
    518 		s_lastbrushcount = g_numbrushes;
    519 		s_lastentitycount = g_numentities;
    520 		s_didonce = true;
    521 	}
    522 }
    523 
    524 char		com_token[1024];
    525 qboolean	com_eof;
    526 
    527 /*
    528 ================
    529 I_FloatTime
    530 ================
    531 */
    532 double I_FloatTime (void)
    533 {
    534 	time_t	t;
    535 	
    536 	time (&t);
    537 	
    538 	return t;
    539 #if 0
    540 // more precise, less portable
    541 	struct timeval tp;
    542 	struct timezone tzp;
    543 	static int		secbase;
    544 
    545 	gettimeofday(&tp, &tzp);
    546 	
    547 	if (!secbase)
    548 	{
    549 		secbase = tp.tv_sec;
    550 		return tp.tv_usec/1000000.0;
    551 	}
    552 	
    553 	return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0;
    554 #endif
    555 }
    556 
    557 
    558 /*
    559 ==============
    560 COM_Parse
    561 
    562 Parse a token out of a string
    563 ==============
    564 */
    565 char *COM_Parse (char *data)
    566 {
    567 	int		c;
    568 	int		len;
    569 	
    570 	len = 0;
    571 	com_token[0] = 0;
    572 	
    573 	if (!data)
    574 		return NULL;
    575 		
    576 // skip whitespace
    577 skipwhite:
    578 	while ( (c = *data) <= ' ')
    579 	{
    580 		if (c == 0)
    581 		{
    582 			com_eof = true;
    583 			return NULL;			// end of file;
    584 		}
    585 		data++;
    586 	}
    587 	
    588 // skip // comments
    589 	if (c=='/' && data[1] == '/')
    590 	{
    591 		while (*data && *data != '\n')
    592 			data++;
    593 		goto skipwhite;
    594 	}
    595 	
    596 
    597 // handle quoted strings specially
    598 	if (c == '\"')
    599 	{
    600 		data++;
    601 		do
    602 		{
    603 			c = *data++;
    604 			if (c=='\"')
    605 			{
    606 				com_token[len] = 0;
    607 				return data;
    608 			}
    609 			com_token[len] = c;
    610 			len++;
    611 		} while (1);
    612 	}
    613 
    614 // parse single characters
    615 	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
    616 	{
    617 		com_token[len] = c;
    618 		len++;
    619 		com_token[len] = 0;
    620 		return data+1;
    621 	}
    622 
    623 // parse a regular word
    624 	do
    625 	{
    626 		com_token[len] = c;
    627 		data++;
    628 		len++;
    629 		c = *data;
    630 	if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':')
    631 			break;
    632 	} while (c>32);
    633 	
    634 	com_token[len] = 0;
    635 	return data;
    636 }
    637 
    638 
    639 
    640 /*
    641 =============================================================================
    642 
    643 						MISC FUNCTIONS
    644 
    645 =============================================================================
    646 */
    647 
    648 
    649 int		argc;
    650 char	*argv[MAX_NUM_ARGVS];
    651 
    652 /*
    653 ============
    654 ParseCommandLine
    655 ============
    656 */
    657 void ParseCommandLine (char *lpCmdLine)
    658 {
    659 	argc = 1;
    660 	argv[0] = "programname";
    661 
    662 	while (*lpCmdLine && (argc < MAX_NUM_ARGVS))
    663 	{
    664 		while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126)))
    665 			lpCmdLine++;
    666 
    667 		if (*lpCmdLine)
    668 		{
    669 			argv[argc] = lpCmdLine;
    670 			argc++;
    671 
    672 			while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126)))
    673 				lpCmdLine++;
    674 
    675 			if (*lpCmdLine)
    676 			{
    677 				*lpCmdLine = 0;
    678 				lpCmdLine++;
    679 			}
    680 			
    681 		}
    682 	}
    683 }
    684 
    685 
    686 
    687 /*
    688 =================
    689 CheckParm
    690 
    691 Checks for the given parameter in the program's command line arguments
    692 Returns the argument number (1 to argc-1) or 0 if not present
    693 =================
    694 */
    695 int CheckParm (char *check)
    696 {
    697 	int             i;
    698 
    699 	for (i = 1;i<argc;i++)
    700 	{
    701 		if ( stricmp(check, argv[i]) )
    702 			return i;
    703 	}
    704 
    705 	return 0;
    706 }
    707 
    708 
    709 
    710 
    711 /*
    712 ==============
    713 ParseNum / ParseHex
    714 ==============
    715 */
    716 int ParseHex (char *hex)
    717 {
    718 	char    *str;
    719 	int    num;
    720 
    721 	num = 0;
    722 	str = hex;
    723 
    724 	while (*str)
    725 	{
    726 		num <<= 4;
    727 		if (*str >= '0' && *str <= '9')
    728 			num += *str-'0';
    729 		else if (*str >= 'a' && *str <= 'f')
    730 			num += 10 + *str-'a';
    731 		else if (*str >= 'A' && *str <= 'F')
    732 			num += 10 + *str-'A';
    733 		else
    734 			Error ("Bad hex number: %s",hex);
    735 		str++;
    736 	}
    737 
    738 	return num;
    739 }
    740 
    741 
    742 int ParseNum (char *str)
    743 {
    744 	if (str[0] == '$')
    745 		return ParseHex (str+1);
    746 	if (str[0] == '0' && str[1] == 'x')
    747 		return ParseHex (str+2);
    748 	return atol (str);
    749 }
    750 
    751