QE3.CPP 14 KB

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